9

A module holds a dictionary to keep track of itscontext, such as the names defined at some point of the execution. This dictionary can be accessed through vars(module) (or module.__dict__) if module was imported, or by a call to the locals built-in function in the module itself:

Update and return a dictionary representing the current local symbol table.

But I found myself a bit confused, when I tried accessing the locals dictionary from a function. The output of a script containing only the following is an empty dictionary:

def list_locals():
    print(locals())

list_locals()

But on the other hand, if a script contains exclusively the following, the output is the expected dictionary, containing __name__, __doc__ and the other module-level variables:

print(locals())

So, when is the content of the locals dictionary set? In addition, what does "update" mean in the definition of the locals function?

Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997
Right leg
  • 13,581
  • 5
  • 36
  • 68

2 Answers2

9

The namespace of a module is the global namespace, accessed through globals(). There is no separate locals namespace, so locals(), outside of functions, just returns the global namespace.

Only functions have a local namespace. Note that locals() is a one-way reflection of that namespace; the CPython implementation for functions is highly optimised and you can't add or alter local variables through the locals() dictionary. The dictionary returned by locals() is updated whenever the namespace has changed between calls to that function.

Note also that things like list / dict / set comprehensions, generator expressions and class bodies are in reality executed as functions too, albeit with different namespace rules. In such contexts locals() will also return the separate function local namespace.

Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997
1

If you call locals() more than once during the same function call, it will return the same dictionary.

>>> def f():
...     d = locals()
...     assert 'd' not in d
...     locals()
...     assert 'd' in d
...     assert d is locals()
...     print(d)
... 
>>> f()
{'d': {...}}

"Update" in this case means that the contents of this dictionary are updated to reflect the current scope of local variables that exist, but if you kept a reference to this dictionary then that dictionary will still be used.

Notice also that the locals dictionary doesn't contain a key for 'f', even though you could have accessed it during the course of the function. In case it's not obvious, that's a global, not a local.

Josh Lee
  • 149,877
  • 34
  • 253
  • 263
  • Thanks for that explanation about the meaning of "update". Although I obviously mixed up `locals` and `globals`, I'd say that the documentation is somewhat evasive about that behaviour. Thanks again for the clarification. – Right leg Sep 07 '17 at 12:20