关于python:Python3 globals()和locals()内容

Python3 globals() and locals() contents

在我的python3学习中,在尝试globals()和locals()的同时,我制作了一个非常基本的、独立的python程序,并收到了一些结果,我需要专家的解释。

然后,我在我的python程序(any)中执行了相同的2个函数,并收到了许多(all?)的列表。我的程序中的值,无论它是声明为本地、全局还是非。

我的理解是globals()函数包含声明为globals的所有值的列表(对于局部变量也是如此),但是根据我的观察,结果显示出了一些不同的东西。

有人能解释我所看到的和为什么吗?

下面是程序和结果:

python程序:

1
2
 print("Globals=",globals())
 print("Locals=",locals())

结果(对于上述两行程序):

1
2
3
4
5
6
7
8
9
10
=============== 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()是指当前模块的属性字典。locals()是指函数/代码片段中的当前局部变量。

设置变量只会更改locals()。(除非您使用globalnonlocal关键字告诉python其他情况。)

这里举个例子

默认情况下,模块作用域全局变量与局部变量的dict相同:

1
2
>>> globals() is locals()
True

在这种情况下,全局是局部的,修改局部也将修改全局。

如果您创建一个函数并查看其中的局部变量,您将看到局部变量将不同

1
2
3
4
5
6
7
8
>>> def test():
...    print("globals is locals:", globals() is locals())
...    print("globals:", globals())
...    print("locals:", locals())
>>> test()
globals is locals: False
globals: {'__name__': '__main__', ...}
locals: {}

当您更改函数局部变量时,局部变量将自动更新

1
2
3
4
5
6
7
>>> def test2():
...     print("locals 1:", locals())
...     x = 1
...     print("locals 2:", locals())
>>> test2()
locals 1: {}
locals 2: {'x': 1}

创建新类时也会发生类似的情况

1
2
3
>>> class Test:
...     print("locals:", locals())
locals: {'__module__': '__main__', '__qualname__': 'Test'}

。更深入的解释

如果你想知道为什么全球人和当地人都是这样,让我们看看在Python的引擎盖下会发生什么。

一些地面工程

所有python代码都会在某个时刻传递等同于evalexec函数的代码。这些函数接受三个参数:sourceglobals(默认为当前全局变量)和locals(默认为当前局部变量)。

函数globals()locals()将返回已传递到evalexec函数中的任何内容。

python shell做什么?

如果你愿意的话

1
>>> print(globals())

repl将在内部执行以下操作:

1
2
3
4
5
6
7
8
9
# 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())")

如您所见,python shell将在某个时刻将globalslocals设置为同一个dict。

函数执行

在内部,函数执行基本上要做三件事:

  • 分析传递给函数的参数,并将它们添加到局部变量中。
  • 执行函数的代码
  • 返回结果。
  • 这里是一个伪算法:

    1
    2
    3
    4
    def __call__(*args, **kwargs):
        local_variables = parse_signature_with_args(args, kwargs)
        exec(function_source, function_globals, local_variables)
        return function_result

    创建新类

    使用class语句时,所有缩进代码都将单独执行。

  • 创建了一个新的字典,它将充当locals()的角色。
  • 您的代码是用上述本地人执行的。
  • 类是通过传入局部变量创建的
  • 如果执行此代码:

    1
    2
    class Test:
       a = 5

    这大概是发生的事情:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     # 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)

    如何映射到模块导入

    如果导入模块,则会启动复杂的导入机制。这是一个简单的概述:

  • 解释器将查看模块是否已导入。
  • 解释器将找到该文件。
  • 然后读取并分析文件
  • 将创建模块对象。
  • 将执行python脚本,并将其全局和局部变量设置为新模块的__dict__属性。
  • 返回模块对象。
  • 它的工作原理如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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