考虑以下代码:
class B(object):
def __init__(self):
self.b = 2
def foo(self):
out1 = [eval('self.b')] # ok
print(out1) # prints: [2]
out2 = [eval(cmd) for cmd in ['self.b']] # fails
print(out2) # NameError: name 'self' is not defined
b = B()
b.foo()
为什么
out1
的语句可以,但 out2
的语句不行,会出现“‘self’未定义”错误?
我正在学习Python,我在实验
eval
时遇到了这个问题。是的,我知道在这个例子中使用 eval
是不合适的,但是为了从表面上看这个例子,有人可以解释为什么 out2
的语句给出错误消息吗?看来这两种说法都应该有效并给出相同的结果。
通过使用列表理解,您实际上定义了一个新的范围。事实上,如果我们将列表理解更改为:
out2 = [print(globals()) or print(locals()) or eval(cmd) for cmd in ['self.b']]
我们强制 Python 在调用
eval(..)
之前打印局部变量和全局变量,我们得到如下内容:
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__loader__': <class '_frozen_importlib.BuiltinImporter'>, 'b': <__main__.B object at 0x7f406f55d4a8>, '__doc__': None, '__package__': None, 'B': <class '__main__.B'>, '__spec__': None}
{'.0': <list_iterator object at 0x7f406f55df28>, 'cmd': 'self.b'}
因此,作为局部变量,我们只有一个
.0
和一个 cmd
。
但是,您可以使用以下方法将
self
传递给列表理解:
globs = globals()
locs = locals()
out2 = [eval(cmd,globs,locs) for cmd in ['self.b']]
所以现在
eval(..)
将使用函数范围中定义的局部变量和全局变量。因为我们使用 locs
和 globs
。 Python 将对这些字典的引用传递给 eval(..)
调用。
最后警告每次使用
eval(..)
时:eval 是一个危险的函数。你最好只在确实需要时才使用它。
这个附加作用域的另一个副作用(在python-3.x中引入)是循环变量不会泄漏:在列表理解cmd
被清理之后:你无法再访问它(通常它会保存它处理的最后一个元素)。例如:
>>> [x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined