eval 列表理解失败[重复]

问题描述 投票:0回答:1

考虑以下代码:

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
的语句给出错误消息吗?看来这两种说法都应该有效并给出相同的结果。

python python-3.x eval list-comprehension
1个回答
12
投票

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

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 是一个危险的函数。你最好只在确实需要时才使用它。

这个附加作用域的另一个副作用(在中引入)是循环变量不会泄漏:在列表理解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
    
© www.soinside.com 2019 - 2024. All rights reserved.