【问题标题】:eval fails in list comprehension [duplicate]eval 在列表理解中失败 [重复]
【发布时间】:2017-07-19 15:26:50
【问题描述】:

考虑以下假设代码:

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' is not defined”?

我正在学习 Python,在尝试 eval 时遇到了这个问题。是的,我知道在这个例子中使用eval 是不合适的,但只是为了从表面上看这个例子,有人可以解释为什么out2 的语句会给出错误消息吗?看来这两个语句都应该起作用并给出相同的结果。

感谢您的指导。

【问题讨论】:

  • 因为您使用列表理解定义了一个没有自我的新范围?
  • 请注意,您的代码可以在 Python 2 中运行,因为当时 LC 并没有引入新的作用域。

标签: python python-3.x eval list-comprehension


【解决方案1】:

通过使用列表推导,您实际上定义了一个新范围。事实上,如果我们将列表理解更改为:

out2 = [print(globals()) or print(locals()) or eval(cmd) for cmd in ['self.b']]

在调用 eval(..) 之前,我们强制 Python 打印局部和全局变量,我们会得到类似的结果:

{'__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(..)使用函数范围内定义的局部和全局变量。因为我们使用locsglobs。 Python 会将这些字典的引用传递给eval(..) 调用。

最后一个警告,就像每次使用eval(..) 一样:eval 是一个危险的函数。最好只在真正需要时才使用它。

这个额外作用域(在 中引入)的另一个副作用是循环变量 确实 泄漏:在列表理解cmd 被清除之后up:你不能再访问它(通常它会保存它处理的最后一个元素)。例如:

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

【讨论】:

  • 谢谢你!我读过关于列表推导有自己的范围,但直到现在我才建立联系。
猜你喜欢
  • 2020-02-27
  • 2015-07-08
  • 2021-04-20
  • 2020-04-25
  • 2019-08-13
  • 2011-05-23
  • 2017-09-25
  • 1970-01-01
  • 2011-06-15
相关资源
最近更新 更多