在字典理解中使用eval的NameError

时间:2015-09-24 14:05:49

标签: 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 defined

如果我这样做:

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

这里没有错误。

怎么回事?

2 个答案:

答案 0 :(得分:2)

TL:DR 摘要 -

正如@CoryKramer正确陈述的那样,部分原因是因为字典理解/列表理解/生成器表达式/嵌套函数都在它们自己的范围内进行了评估。但是这个问题的另一半原因是因为使用了eval(),它在调用它的环境中执行它的表达式,但是它无法访问封闭的命名空间。

或者,我相信你不应该使用eval()its pretty dangerous)。要从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)})

结果 -

{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'可以在词典理解中找到(因为它是free variable,这只是因为我直接在词典理解中使用self.a,如果我没有添加它不会是一个自由变量。让我们解释一下自由变量 -

  

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

但是当你使用eval()来执行表达式时,Python不知道eval()中使用的任何名称(事先在执行表达式之前),因此它不能绑定{{ 1}}作为一个自由变量来理解。使用self获取locals() -

eval的打印示例
self.a

结果 -

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

因此,当在eval中评估表达式时,它不会在执行的环境中定义{0: {'.0': <range_iterator object at 0x023739B0>, 'k': 1}, 1: {'.0': <range_iterator object at 0x023739B0>, 'k': 1}} 变量。如果你在词典理解中的任何地方使用self,你就不会得到这个错误 -

self

结果 -

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

因为然后执行{0: 'Hello', 1: 'Hello'} 表达式的环境知道绑定名称eval

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

self

答案 1 :(得分:0)

避免使用 curl -v http://ip-10-0-1-98:7474/db/manage/server/ha/available [ec2-user@ip-10-0-2-98 log]$ curl -v http://ip-10-0-1-98:7474/db/manage/server/ha/available * Trying 10.0.1.98... * Connected to ip-10-0-1-98 (10.0.1.98) port 7474 (#0) > GET /db/manage/server/ha/available HTTP/1.1 > User-Agent: curl/7.40.0 > Host: ip-10-0-1-98:7474 > Accept: */* > < HTTP/1.1 404 Not Found < Date: Thu, 24 Sep 2015 13:06:52 GMT < Content-Type: text/plain < Access-Control-Allow-Origin: * < Transfer-Encoding: chunked < Server: Jetty(9.2.4.v20141103) < * Connection #0 to host ip-10-0-1-98 left intact 。更好的做法是使用eval

getattr