请考虑此代码:
from sklearn.model_selection import ParameterGrid
def conf1():
return {"p1": [1,2], "p2": [4,5,6]}
def f(aa, bb, cc):
c = locals()
print("CONFIG, locals():")
for k, v, in c.items():
print(f"{k}: {v}")
#>
params = eval("conf1()")
grid = ParameterGrid(params)
#<
d = {**c}
print("CONF after eval")
for k, v, in d.items():
print(f"{k}: {v}")
f(1,2,3)
其输出为:
CONFIG, locals():
aa: 1
bb: 2
cc: 3
CONF after eval
aa: 1
bb: 2
cc: 3
c: {'aa': 1, 'bb': 2, 'cc': 3, 'c': {...}, 'k': 'cc', 'v': 3}
k: cc
v: 3
函数f
用它的本地名称,特别是它接收的参数,创建一个字典c
。然后由CCD_ 3创建一个新的字典。然后,创建一个新的字典d = {**c}
。
似乎当执行c = {**d}
时,d = locals()
被重新评估。由于此时本地环境还包含k
、v
和d
,因此它们最终位于d
中。如果我删除eval
(#>
和#<
之间的行(,我会得到我所期望的,即c
和d
包含相同的项。
可能是评估不是原因,但我不能真正理解发生了什么。我找不到任何解释。有什么帮助吗?
由于在评论中我读到CCD_;locals(("我做了这个测试:
def f(param1, param2):
config = locals()
print("1. config:")
for k, v in config.items():
print(f"- {k}: {v}")
name =1
print("2. config:")
for k, v in config.items():
print(f"- {k}: {v}")
f(1, 2)
输出:
1. config:
- param2: 2
- param1: 1
2. config:
- param2: 2
- param1: 1
因此,它似乎并不那么多变。
如果添加eval
:
def f(param1, param2):
config = locals()
print("1. config:")
for k, v in config.items():
print(f"- {k}: {v}")
name = 1
eval("print()")
print("2. config:")
for k, v in config.items():
print(f"- {k}: {v}")
f(1, 2)
再次:
1. config:
- param2: 2
- param1: 1
2. config:
- param2: 2
- param1: 1
- name: 1
- v: 1
- k: param1
- config: {'param2': 2, 'param1': 1, 'name': 1, 'v': 1, 'k': 'param1', 'config': {...}}
@juanpa.arrivilaga发表评论后,我得到了它,并且能够在没有eval()
:的情况下进行复制
def f(param1, param2):
config = locals()
print("1. config:")
for k, v in config.items():
print(f"- {k}: {v}")
name = "hello"
locals()
print("2. config:")
for k, v in config.items():
print(f"- {k}: {v}")
f(1, 2)
输出:
1. config:
- param2: 2
- param1: 1
2. config:
- param2: 2
- param1: 1
- name: hello
- v: 1
- k: param1
- config: {'param2': 2, 'param1': 1, 'name': 'hello', 'v': 1, 'k': 'param1', 'config': {...}}
文件上写着:
locals((更新并返回一个表示当前本地符号表。当locals((在函数块中调用,但在类块中不调用。请注意,在模块级别,locals((和globals((是同一个字典。
我会用";。。。返回字典"而不是";a";,但是,无论如何。。。
谢谢大家。
对于将来访问此页面的用户。在阅读了权威来源的示例后,我开始使用config=locals()
来保存一个类似配置的字典,但该赋值不是";正确的";并导致这些奇怪的行为,在复杂的代码中很难发现。
使用locals()
保存配置字典的更好方法是config = {**locals()}
:
def f(param1, param2):
config = {**locals()}
print("1. config:")
for k, v in config.items():
print(f"- {k}: {v}")
name = "hello"
locals()
print("2. config:")
for k, v in config.items():
print(f"- {k}: {v}")
f(1, 2)
具有预期的、正常的行为,尤其是对于习惯于使用变量而不是名称的语言的人来说:
1. config:
- param2: 2
- param1: 1
2. config:
- param2: 2
- param1: 1
我同意公认答案的作者的观点:文档应该更接近实际的语义。
因此,eval
将隐式检索locals()
。来自eval
:的文档
如果省略
locals
字典,则默认为globals
词典如果两个字典都被省略,则表达式为在eval()
所在的环境中使用全局和局部执行被调用。
然后从locals
:上的文档
更新并返回表示当前本地符号表的字典。
所以没有很好地定义精确的行为。但它似乎在重新使用同一个字典,并在每次调用时从实际的本地符号表中更新它。
因此:
>>> def foo():
... l = locals()
... print(l)
... a = 42
... print(l is locals())
... print(l)
... b = 11
... print(l)
...
>>> foo()
{}
True
{'l': {...}, 'a': 42}
{'l': {...}, 'a': 42}
>>>