Storing information in `sys.settrace`/`sys.setprofile`/ PEP 669

I’d like to do some sort of tracing of function calls that involve storing an arbitrary object between when the function gets called and when it returns or raises an exception.

All of the above methods rely on callbacks and as such there’s no obvious place to store information.

With sys.settrace I believe I can create a closure and return that as the next tracing function, that seems like it should work. But with the others as far as I can tell I have to either (1) keep the state myself or (2) keep my state in the locals of the function in question, which could change how code executes (e.g. if something calls locals()). Keeping state myself seems error-prone. Any suggestions?

1 Like

Have you considered using custom callable objects instead of functions?

from collections.abc import Callable, Sequence


class CallableCounter:
    def __init__(self) -> None:
        self.count = 0

    def __call__(self) -> None:
        self.count += 1


def do_something(callbacks: Sequence[Callable[[], None]]) -> None:
    print("I did something")
    for cb in callbacks:
        cb()


counter = CallableCounter()
for _ in range(10):
    do_something([counter])

assert counter.count == 10

Another option might be to use “context variables”, which might work better if you’re dealing with concurrency:

1 Like