Search code examples
pythoninspectcontextmanager

Access the locals available in the previous stack frame


I have a debug context manager where I would like to access the locals() at the time the context manager was initiated, without giving the locals as an argument. Is this possible?

I would like to do this in the general case, so that my Debug context manager can be used from any file importing Debug, not just in the tinkertoy example below.

Here is my minimal example:

import inspect

class Debug:
    def __init__(self):

        frames = inspect.stack()

        for frame in frames:
            line = frame.code_context[0]
            if "Debug" in line:
                break

        # I want to get the locals() at the time debug was called here!
        # give me i_will_be_in_the_locals
        raise Exception()

    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass


if __name__ == "__main__":

    i_will_be_in_the_locals = 42
    with Debug():
        "hi"

Solution

  • The frame object is inside the "frame" variable you defined. To get the local variables for a frame object, you can call its f_locals attribute like this:

    import inspect
    
    class Debug:
        def __init__(self):
    
            frames = inspect.stack()
    
            for frame in frames:
                line = frame.code_context[0]
                if "Debug" in line:
                    break
    
            # I want to get the locals() at the time debug was called here!
            # give me i_will_be_in_the_locals
            from pprint import pprint
            pprint(frame.frame.f_locals)
    
        def __enter__(self):
            pass
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            pass
    
    
    if __name__ == "__main__":
    
        i_will_be_in_the_locals = 42
        with Debug():
            "hi"
    

    The returned value is:

    {'Debug': <class '__main__.Debug'>,
     '__builtins__': <module 'builtins' (built-in)>,
     '__cached__': None,
     '__doc__': None,
     '__file__': '/home/user1/main-projects/overflow/file.py',
     '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f7bbb44f7f0>,
     '__name__': '__main__',
     '__package__': None,
     '__spec__': None,
     'i_will_be_in_the_locals': 42,
     'inspect': <module 'inspect' from '/usr/lib/python3.5/inspect.py'>}