Hacker News new | ask | show | jobs
by sillysaurusx 1973 days ago

  from watchpoints import watch

  a = []
  watch(a)
  a.append(1)  # Trigger
  a = {}  # Trigger
HOW?! I demand an explanation.

How does the second trigger fire? Deterministically, without relying on GC tricks? It’s watching a variable name, somehow.

Does it hook into globals()? But how would it know it needs to?

1 comments

It uses Python's built-in inspect module to get the caller frame. https://github.com/gaogaotiantian/watchpoints/blob/68bc13716...

It then uses sys.settrace (which is intended as an interface for debuggers) to step through the code and check whether the variable has been changed. Documentation on sys.settrace: https://docs.python.org/3/library/sys.html#sys.settrace

Python exposes most of its guts as part of the standard library, making clever hacks like this possible.

Does this incur a performance penalty? What I mean is, could you theoretically write code this way with no ill effects?

Not that you’d want to, but it’s a fun thought experiment.

lol, thank you for the attention. Yes this will incur a performance penalty, and is similar to what "pdb" introduces(if your are familiar with pdb). Most of the python debugger did single step or breakpoint feature in this way.

And it's a little more than inspect and frames. Note that it is much easier to do watch("a") than watch(a), but it's slightly less intuitive. So I also did some AST hack to make watch(a) possible :)

Please make more stuff :)

Are you on Twitter or anything? I'd like to follow your work. (Put some info in your HN profile!)

I noticed that watchpoints doesn't work in the REPL, and since I live in the REPL, it limits my usage somewhat. But after digging into the code, I'm not quite sure if it even makes sense in the context of <stdin>...

I was also -- as the other commenter said, excuse the french -- fucking amazed that this works great:

    from watchpoints import watch

    a = []
    watch(a)
    a.append(1)  # Trigger
    a = {}  # Trigger

    def qq():
      global a
      a = 99 # Trigger


    qq()
Did not expect that.
I'm not on twitter, but I do have a twitter account for my other project viztracer @viztracer. All my work is on my github if you are interested :)

watchpoints does not work in the REPL. REPL is a more complicated environment. I don't think pdb will work in REPL either.

watchpoints works very intuitively. It has some dirty magic that made it work in some way that you need but not expect.