在字典理解中使用 eval 时出现 NameError

2023-11-30

我正在尝试在我的班级中编写字典:

data = {element:eval("self.%s" %element) for element in key}   

我有这个错误:

data = {element:eval("self.%s" %element) for element in key}
        File "<string>", line 1, in <module>
        NameError: name 'self' is not defined

If I do:

 for element in key:
     data[element]=eval("self.%s" %element)

这里没有错误。

怎么会?


TL:DR概括 -

正如 @CoryKramer 正确指出的,部分原因是字典理解/列表理解/生成器表达式/嵌套函数都在自己的范围内进行评估。但此问题的另一半原因是由于使用eval(),它在调用它的环境中执行其表达式,但它无权访问封闭的名称空间。

另外,我相信你不应该使用eval() (这很危险)。用于获取属性self,你应该使用getattr()功能 -

data = {element:getattr(self,element) for element in key}

对于那些感兴趣的人,我对这个问题的发现 -

部分原因是字典理解/列表理解/生成器表达式/嵌套函数都在自己的范围内进行评估。但此问题的另一半原因是由于使用eval() .

正如文档中给出的eval() -

eval(expression[, globals[, locals]])

如果两个字典都被省略,则表达式将在调用 eval() 的环境中执行。返回值是计算表达式的结果。语法错误被报告为异常。

(强调我的)

通常在课堂上,当您使用字典理解时,您可以使用self等等在字典理解中。例子 -

>>> class CA:
...     def __init__(self):
...             self.a = "Hello"
...             print({k:self.a for k in range(2)})
...
>>> CA()
{0: 'Hello', 1: 'Hello'}
<__main__.CA object at 0x008B22D0>

如您所见,可以访问self.a在字典理解范围内。现在让我们检查一下是什么locals()(本地命名空间)用于字典理解 -

... #same as above, just change the print function call.
print({k:locals() if k < 2 else self.a for k in range(2)})

Result -

{0: {'.0': <range_iterator object at 0x02373998>, 'self': <__main__.CA object at 0x008B22D0>, 'k': 1}, 
1: {'.0': <range_iterator object at 0x02373998>, 'self': <__main__.CA object at 0x008B22D0>, 'k': 1}}

可以看出'self'可以在字典理解中访问(因为它是自由变量,这只是因为我使用了self.a直接在字典理解中,如果我没有添加它在那里就不是一个自由变量。让我们解释一下自由变量 a bit -

如果名称绑定在块中,则它是该块的局部变量。如果名称绑定在模块级别,则它是全局变量。 (模块代码块的变量有局部变量和全局变量。)如果一个变量在代码块中使用但未在代码块中定义,则它是一个变量自由变量.

但是当你使用eval()为了执行表达式,Python 不知道在表达式内部使用的任何名称(事先,在执行表达式之前)eval(),因此它不能绑定self作为字典理解的自由变量。打印示例locals(),当使用eval to get self.a -

...
print({k:locals() if k < 2 else eval('self.a') for k in range(2)})

Result -

{0: {'.0': <range_iterator object at 0x023739B0>, 'k': 1}, 1: {'.0': <range_iterator object at 0x023739B0>, 'k': 1}}

因此,当在 eval 内计算表达式时,它没有self在执行环境中定义的变量。如果你要使用self在字典理解中的任何地方,您都不会出现此错误 -

...
print({k:eval('self.a') if k < 2 else self for k in range(2)})

Result -

{0: 'Hello', 1: 'Hello'}

因为那时的环境eval正在执行的表达式知道名称绑定self .

也可以使用嵌套函数来复制完全相同的问题 -

>>> def a():
...     localb = 10
...     def c():
...             print(locals())
...             print(eval('localb + 20'))
...     c()
...
>>> a()
{}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in a
  File "<stdin>", line 5, in c
  File "<string>", line 1, in <module>
NameError: name 'localb' is not defined
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在字典理解中使用 eval 时出现 NameError 的相关文章

随机推荐