在字典理解内使用eval的NameError [英] NameError using eval inside dictionary comprehension

查看:179
本文介绍了在字典理解内使用eval的NameError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to code a dictionary inside my class:

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

如果我这样做:

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

这里没有错误.

怎么来?

推荐答案

TL:DR 摘要-

正如@CoryKramer正确指出的,部分原因是因为字典理解/列表理解/生成器表达式/嵌套函数都在它们自己的范围内求值.但是造成此问题的另一半原因是由于使用了eval(),它可以在调用它的环境中执行其表达式,但不能访问封闭的名称空间.

As stated correctly by @CoryKramer , partially this is because dictionary comprehension/list comprehension/generator expressions/nested funcions all are evaluated in their own scope. But other half of the reason for this issue is because of the use of eval() , which executes its expressions in the environment in which it is called , but it does not have access to enclosing namespaces.

或者,我认为您不应该使用eval()(非常危险) .为了从self获取属性,您应该使用 getattr() 函数-

Alternatively ,I believe you should not use eval() (its pretty dangerous) . For getting attributes from self , you should use getattr() function -

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


我对感兴趣的人的调查结果-


My findings about the issue for those who are interested -

部分原因是因为字典理解/列表理解/生成器表达式/嵌套函数都在它们自己的范围内求值.但是造成此问题的另一半原因是由于使用了eval().

Partially this is because dictionary comprehension/list comprehension/generator expressions/nested funcions all are evaluated in their own scope. But other half of the reason for this issue is because of the use of eval() .

eval()- 文档中所给出的>

As given in the documentation for eval() -

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

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

If both dictionaries are omitted, the expression is executed in the environment where eval() is called. The return value is the result of the evaluated expression. Syntax errors are reported as exceptions.

(强调我的)

通常在一个类中,当您使用字典理解时,可以在该字典理解中使用self等.示例-

Normally inside a class , when you use dictionary comprehension you can use self and etc in that dictionary comprehension. Example -

>>> 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()(本地名称空间)是什么-

As you can see it was possible to access self.a within the dictionary comprehension. So now lets check what is the locals() (local namespace) for the dictionary comprehension -

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

结果-

{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,如果我没有添加,那就不是那里的免费变量. .让我们稍微解释一下自由变量-

As can be seen 'self' is accessible inside the dictionary comprehension (as its a free variable , and this only occured because I used self.a directly inside the dictionary comprehension , if I did not add that it wouldn't be a free variable there. Lets explain free variables a bit -

如果名称绑定在块中,则该名称是该块的局部变量.如果名称在模块级别绑定,则它是全局变量. (模块代码块的变量是局部变量和全局变量.)如果在代码块中使用了变量但未在其中定义,则该变量为 free变量.

但是当您使用eval()执行表达式时,Python不知道eval()内部使用的任何名称(之前,在执行表达式之前),因此它无法将self绑定为自由对二元理解的变量.使用eval获取self.a-

But when you use eval() to execute the expression, Python does not know about any names (beforehand, before executing the expression) that are used inside the eval() , hence it cannot bind the self as a free variable to the dicitonary comprehension. Example of print of locals() , when using eval to get self.a -

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

结果-

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

因此,当在eval内对表达式求值时,它没有在执行环境中定义的self变量.如果要在字典理解范围内的任何地方使用self,则最终不会出现此错误-

Hence, when the expression is evaluated inside the eval it does not have the self variable defined in the environment it is executed. If you were to use self anywhere inside the dictionary comprehension , you would not end up with this error -

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

结果-

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

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

Because then the environment in which eval expression is getting executed has knows about the name binding self .

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

The exact same issue can be replicated using nested functions as well -

>>> 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

这篇关于在字典理解内使用eval的NameError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆