In my Python3 learning, while trying out globals() and locals(), I made a very basic, stand-alone Python program and received results for which I ask for expert explanation.
I then executed the same 2 functions inside my Python program (any) and received a list of many (all ?) values in my program, regardless if it was declared local or global or non. My understanding was that the globals() functions holds a list of all values that were declared as globals (same for locals), but according to my observation, the results show something different. Can anyone explain what I see and why?Here is the program and the results:
The python program:
print("Globals=",globals())
print("Locals=",locals())
The result (for the above 2-lines program):
=============== RESTART: /home/pi/Junk/globals_locals_test.py ==========
Globals= {'__package__': None, '__spec__': None, '__loader__': <class '
_frozen_importlib.BuiltinImporter'>, '__doc__': None, '__file__': '
/home/pi/Junk/globals_locals_test.py', '__builtins__': <module 'builtins'
(built-in)>, '__name__': '__main__'}
Locals= {'__package__': None, '__spec__': None, '__loader__': <class '
_frozen_importlib.BuiltinImporter'>, '__doc__': None, '__file__': '
/home/pi/Junk/globals_locals_test.py', '__builtins__': <module 'builtins'
(built-in)>, '__name__': '__main__'}
>>>
globals()
refers to the current modules' attribute dictionary. locals()
refers to the current local variables in your function/code-snippet.
Setting a variable will only ever change locals()
. (Unless you tell python otherwise using the global
or nonlocal
keyword.)
Here an example
By default on module-scope globals is the same dict as locals:
>>> globals() is locals()
True
Since globals is locals in this case, modifying the locals will also modify the globals.
If you create a function and look at locals in there, you will see that locals will differ
>>> def test():
... print("globals is locals:", globals() is locals())
... print("globals:", globals())
... print("locals:", locals())
>>> test()
globals is locals: False
globals: {'__name__': '__main__', ...}
locals: {}
Locals will automatically update when you change a function-local variable
>>> def test2():
... print("locals 1:", locals())
... x = 1
... print("locals 2:", locals())
>>> test2()
locals 1: {}
locals 2: {'x': 1}
Something similar happens when creating new classes
>>> class Test:
... print("locals:", locals())
locals: {'__module__': '__main__', '__qualname__': 'Test'}
If you want to know why globals and locals are the way they are let's look at what happens under the hood of Python.
Some ground work
All python code passes what equates to the eval
or exec
function at some point. These functions accept three parameters: source
, globals
(defaults to current globals) and locals
(defaults to current locals).
The function globals()
and locals()
will return whatever has been passed into the eval
or exec
functions shown above.
What does the Python Shell do?
If you do
>>> print(globals())
The REPL will internally do something along the lines of
# This variable stores your globals.
_my_main_module = {}
def exec_some_line(line):
return eval(line, globals=_my_main_module, locals=_my_main_module)
# ...
exec_some_line("print(globals())")
As you can see, the Python Shell will at some point set globals
and locals
to the same dict.
Function execution
Internally, function execution will essentially do three things:
Here a pseudo-algorithm:
def __call__(*args, **kwargs):
local_variables = parse_signature_with_args(args, kwargs)
exec(function_source, function_globals, local_variables)
return function_result
Creating new classes
When using the class-statement, all indented code will be executed separately.
locals()
If you execute this code:
class Test:
a = 5
This is approximately what happens:
# 1. A new dictionary is created
_dict = type.__prepare__()
_dict["__module__"] = __name__
_dict["__qualname__"] = "Test"
# 2. Execute the code
exec("a = 5", globals=globals(), locals=_dict)
# 3. A class is created
Test = type("Test", (), _dict)
How this maps to module imports
If you import a module an intricate import mechanism starts. This is a simplified overview:
__dict__
attribute.It works something like this:
import sys
from types import ModuleType
def __import__(name):
# 1. See if module is already imported
if name in sys.modules:
return sys.modules[name]
# 2. Find file.
filename = find_out_path_to_file(name)
# 3. Read and parse file
with open(filename) as f:
script = f.read()
# 4. Create the new module
module = ModuleType(name)
# 5. Execute the code of the module.
exec(script, globals=module.__dict__, locals=module.__dict__)
# 6. Return the new module.
return module
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments