Python 在字典理解中使用eval时发生名称错误

Python 在字典理解中使用eval时发生名称错误,python,class,dictionary,Python,Class,Dictionary,我正在尝试在我的类中编写字典: 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 defin

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

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
这里没有错误


为什么会这样?

TL:DR总结-

正如@CoryKramer所正确指出的,这部分是因为字典理解/列表理解/生成器表达式/嵌套函数都在各自的范围内求值。但是这个问题的另一半原因是因为使用了
eval()
,它在调用它的环境中执行它的表达式,但是它没有访问封闭名称空间的权限

或者,我认为您不应该使用
eval()
()。要从
self
获取属性,应使用函数-

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

我对这个问题的发现是为那些感兴趣的人准备的-

部分原因是因为字典理解/列表理解/生成器表达式/嵌套函数都在各自的范围内求值。但这个问题的另一半原因是使用了
eval()

如以下文件所示:

eval(表达式[,全局[,局部]])

如果省略了这两个字典,则表达式将在调用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>
结果-

{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}}
{0: {'.0': <range_iterator object at 0x023739B0>, 'k': 1}, 1: {'.0': <range_iterator object at 0x023739B0>, 'k': 1}}
{0: 'Hello', 1: 'Hello'}
结果-

{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}}
{0: {'.0': <range_iterator object at 0x023739B0>, 'k': 1}, 1: {'.0': <range_iterator object at 0x023739B0>, 'k': 1}}
{0: 'Hello', 1: 'Hello'}
结果-

{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}}
{0: {'.0': <range_iterator object at 0x023739B0>, 'k': 1}, 1: {'.0': <range_iterator object at 0x023739B0>, 'k': 1}}
{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
>>定义a():
...     localb=10
...     def c():
...             打印(局部变量())
...             打印(eval('localb+20'))
...     c()
...
>>>()
{}
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第7行,在
文件“”,第5行,c语言
文件“”,第1行,在
NameError:未定义名称“localb”

避免使用
eval
。更好的做法是使用
getattr

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

列表理解、dict理解、生成器表达式等都有自己的范围。看,我不认为重复的问题完全回答了这个问题。这与
eval()
也有点相关。为什么要这样做(
eval
)?您知道
getattr(self,element)
,这会更容易些吗?