【问题标题】:Python3 globals() and locals() contentsPython3 globals() 和 locals() 内容
【发布时间】:2019-02-18 00:24:07
【问题描述】:

在我的 Python3 学习中,在尝试 globals() 和 locals() 时,我编写了一个非常基本的独立 Python 程序并收到了结果我要求专家解释一下。 p> 然后,我在我的 Python 程序(任意)中执行了相同的 2 个函数,并在我的程序中收到了许多(全部?)值的列表,无论它是声明为本地的还是全局的还是非的。 我的理解是 globals() 函数包含一个声明为全局变量的所有值的列表(对于本地变量也是如此),但根据我的观察,结果显示出一些不同的东西。 谁能解释我所看到的以及为什么?

这是程序和结果:

python 程序:

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

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

=============== 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__'}
>>>

【问题讨论】:

标签: python python-3.5 globals


【解决方案1】:

简单说明

globals() 引用当前模块的属性字典。 locals() 指的是你的函数/code-sn-p 中的当前局部变量。

设置一个变量只有会改变locals()。 (除非你告诉 python 否则使用 globalnonlocal 关键字。)

这里是一个例子

默认情况下,模块范围的全局变量与本地变量的字典相同:

>>> globals() is locals()
True

由于在这种情况下全局变量是局部变量,因此修改局部变量也会修改全局变量。

如果您创建一个函数并查看其中的局部变量,您会发现局部变量会有所不同

>>> def test():
...    print("globals is locals:", globals() is locals())
...    print("globals:", globals())
...    print("locals:", locals())
>>> test()
globals is locals: False
globals: {'__name__': '__main__', ...}
locals: {}

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

>>> def test2():
...     print("locals 1:", locals())
...     x = 1
...     print("locals 2:", locals())
>>> test2()
locals 1: {}
locals 2: {'x': 1}

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

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

更深入的解释

如果您想知道为什么全局变量和局部变量是这样的,那么让我们看看 Python 底层发生了什么。

一些基础工作

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

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

Python Shell 有什么作用?

如果你这样做

>>> print(globals())

REPL 将在内部做一些类似的事情

# 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 设置为同一个字典。

函数执行

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

  1. 解析传递给函数的参数并将它们添加到局部变量中。
  2. 执行函数的代码
  3. 返回结果。

这里是一个伪算法:

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

创建新类

使用class-statement时,所有缩进的代码都将单独执行。

  1. 创建了一个新字典,它将充当locals()
  2. 您的代码是由所述本地人执行的。
  3. 类是通过传入本地人创建的

如果你执行这段代码:

class Test:
   a = 5

大概是这样的:

 # 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)

如何映射到模块导入

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

  1. 解释器会查看模块是否已经被导入。
  2. 解释器会找到该文件。
  3. 然后读取并解析文件
  4. 创建了一个模块对象。
  5. python 脚本被执行,它的全局变量和局部变量将被设置为新模块的__dict__ 属性。
  6. 模块对象被返回。

它的工作原理是这样的:

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

【讨论】:

  • 很好的解释。谢谢。虽然这需要更深入的调查和更多的时间来消化细节,但它回答了我的问题。
  • 谢谢。如果对您有帮助,请接受我的回答。
  • Python 实际上并没有在大多数时候使用locals() dict 进行局部变量查找。在函数内部,写入locals() 不会影响局部变量,写入局部变量不会影响局部变量dict,直到您再次调用locals()
  • 有趣的观察。没想到。当查看反汇编的功能时,它变得特别清楚。接得好。有一个 +1。
猜你喜欢
  • 2015-05-18
  • 2011-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-01
  • 2012-07-28
相关资源
最近更新 更多