为什么在本地人中添加密钥实际上会创建变量?

Why add key in locals actually create variable?

我试图创建一个名称中包含空格的变量,我想到了这个:

>>> classic_var = 'spam'
>>> locals()['classic_var'] 
'spam'
>>> classic_var
'spam'
>>> locals()['local_var'] = 'eggs'
>>> locals()['local_var'] 
'eggs'
>>> local_var
'eggs'
>>> locals()['variable with space in names'] = 'parrot'
>>> locals()['variable with space in names']
'parrot'

但有人回复了 (source):

The dictionary returned by locals() just represents the entries in the local symbol table, these are not the symbols themselves. So changing this dictionary does not create any variable at all. See here: https://docs.python.org/3/library/functions.html#locals

所以我想知道为什么这样做有效:

>>> a = 'test'
>>> locals()['a'] = 'hello'
>>> locals()['b'] = 'world'
>>> print(a, b)
hello world

在函数内部,locals 修改不起作用,但在 globals() 中,行为相同。

文档说:“更改可能不会影响解释器使用的局部变量和自由变量的值”。 “可能”。但条件是什么?为什么它“可能”?在什么情况下?

这不是专业项目,只是研究 python 的工作原理以及我们如何调整事物以创造奇怪的事物。

文档中的这一行在这里很重要:

Note that at the module level, locals() and globals() are the same dictionary.

因为你不在函数内部,所以你实际上得到的是交互会话全局变量的字典。

所以像 locals()['a'] = 'hello' 这样的东西实际上创建了一个新的全局变量 a,这在 Python 中完全没问题,因为全局变量与局部变量的工作方式不同。

如果您尝试类似的操作:

def test():
    global global1
    local1 = 'hi'
    global1 = 'ok'
    print(locals())

test()

只显示{'local1': 'hi'}.

如果您尝试过:

def test():
    locals()['local2'] = 'hello world'
    print(local2)

test()

您会收到一个名称错误,指出 local2 未定义。

如果您阅读实际文档,您将看到以下内容:

Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.

该文档未承诺修改字典的效果。


locals()真是奇怪。不仅仅是改变字典对局部变量有不一致的影响——改变局部变量字典.[=22=有不一致的影响]

在全局范围内,或在 class 语句中,字典 locals() returns 是局部范围的实际规范表示。更改字典将更改该范围内的变量,分配变量将更改字典。

在函数范围内,字典 locals() returns 不是局部范围的主要表示。它是附加到堆栈框架的单独字典。调用 locals() 使用局部变量的当前值和 returns 更新字典。

在函数范围内,改变字典通常不会更新局部变量,但在某些特殊情况下(主要与调试有关),Python会从中复制值字典返回局部变量。

在函数范围内,改变局部变量通常不会更新字典,除非你再次调用locals()或者访问框架对象的f_locals属性.调试器访问 f_locals 以读取局部变量值,因此使用 locals() 的代码如果不是为处理此问题而编写的,通常会在调试器中中断:

>>> def f():
...     x = 1
...     y = locals()
...     x = 2
...     print(y['x'])
... 
>>> f()
1
>>> def f():
...     x = 1
...     y = locals()
...     x = 2
...     breakpoint()
...     print(y['x'])
... 
>>> f()
> <stdin>(6)f()
(Pdb) n
2

在这里,添加断点会导致函数打印 2 而不是 1