考虑以下假设代码:
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
的语句会给出错误信息吗?似乎两种陈述都应该起作用并给出相同的结果。
感谢您提供任何指导。
答案 0 :(得分:2)
通过使用列表推导,您实际上定义新范围。确实,如果我们将列表理解改为:
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中引入)是循环变量 不泄漏:列表理解后{{1清理:你不能再访问它(通常它会保存它处理的最后一个元素)。例如:
cmd