locals()字典在使用eval时的奇怪行为

  • 本文关键字:eval 字典 locals python eval
  • 更新时间 :
  • 英文 :


请考虑此代码:

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()被重新评估。由于此时本地环境还包含kvd,因此它们最终位于d中。如果我删除eval(#>#<之间的行(,我会得到我所期望的,即cd包含相同的项。

可能是评估不是原因,但我不能真正理解发生了什么。我找不到任何解释。有什么帮助吗?


由于在评论中我读到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}
>>>

相关内容

  • 没有找到相关文章

最新更新