Search code examples
pythonpython-3.xpython-internals

How are variables looked up in Python?


I have been experimenting with Python and observed some behaviour that I don't understand.

What I think happens when performing a look-up:

  1. Check local variables in current frame
  2. If variable is not found, try first outer frame
  3. Repeat 1 and 2 until there are no more outer frames and if the variable is not found, throw NameError

This is consistent with the 1st call of print(x), as I have forced x into the first outer frame.

However, the 2nd call of print(x) fails with a NameError, which confuses me as x exists in the local variables.

Thanks!

import inspect

def test():

    frame_inner = inspect.currentframe()
    print(locals())  # { 'frame_inner': A }

    frame_outer = inspect.getouterframes(frame_inner)[1].frame
    y = 'y'

    frame_outer.f_locals['x'] = 'x'

    print(locals()) # { 'frame_inner': A, 'frame_outer': B, 'y': 'y' }
    print(y)        # y
    print(x)        # x

    del frame_outer.f_locals['x']

    frame_inner.f_locals['x'] = 'x'

    print(locals()) # { 'frame_inner': A, 'frame_outer': B, 'y': 'y', 'x': 'x' }
    print(y)        # y
    print(x)        # NameError: name 'x' is not defined


test()

Solution

  • If you look at https://docs.python.org/3/library/inspect.html you'll find that all the official usage is for... inspecting the values.

    The inspect module provides several useful functions to help get information about live objects such as modules, classes, methods, functions, tracebacks, frame objects, and code objects.

    No safety of modification is described and you can assume that if you want to modify the frames or other things you get from this module, you're on your own. None of the changes you make are guaranteed to be propagated back to the internal representation of the current state.