使用方法的列表理解中的 eval 范围

Scope within eval in list comprehension with method

我对结合列表理解和 eval 语句的方法感到困惑。下面的代码在 test7 行出错,错误为 NameError: name 'a2' is not defined

class test_class(object):
    def __init__(self):
        pass
    @property
    def property(self):
        return 'test_method_run'

def run():
    a2 = test_class()
    test3 = eval('a.property')
    test4 = [eval('a.property') for i in range(10)]
    test5 = eval('a2.property')
    test6 = [a2.property for i in range(10)]
    test7 = [eval('a2.property') for i in range(10)

a = test_class()
test1 = eval('a.property')
test2 = [eval('a.property') for i in range(10)]
run()

一定和作用域有关()。我对 python 2 中范围的理解(我刚刚转到 python 3)是 a 不应在 run() 中定义,但 a2 是。我对列表理解的影响感到更加困惑。我的期望是 test2test3 行应该失败,因为 a 没有用 test 方法定义。我还预计,如果 test5 运行正常,那么 test6test7 也应该没问题。

只有在函数内的列表推导中使用 eval 时才会出现此错误...如果这 3 个元素中的任何一个不存在,则不会出现错误。我的问题是为什么?我觉得我对它的理解还不足以形成一个更好的问题。

My understanding of scope in python 2 (I have just moved to python 3) was that a should not be defined within run(), but a2 is.

aa2 都在 run 中可见。 a 是在全局范围内定义的,因此它在该文件中随处可见。

I expected that if test5 runs OK then test6 and test7 should also be fine.

在 3.X 中,列表解析有自己的作用域。 test6 列表理解可以访问三个范围:列表理解的范围、函数的范围和全局范围。所以它可以访问 ia2 以及 a.

默认情况下,在 eval 内执行的代码可以访问两个范围:全局范围和最近的本地范围。这意味着 test7 eval 可以访问在文件级别定义的变量,它可以访问列表推导内部定义的变量,但它不能访问函数内部但列表推导之外定义的变量。它可以看到 ai 但看不到 a2.

在 2.7 中,列表推导没有自己的作用域。它们与它们在其中定义的函数共享相同的作用域。这解释了为什么您的代码在 2.7 中执行而不在 3.X 中执行。 IIRC,这是 2.7 和 3.X 之间范围系统的唯一变化。 (如果不是,这是与此场景相关的唯一更改。)