方法的清单理解范围内的范围

时间:2018-11-02 17:10:46

标签: python function list-comprehension eval

我对结合列表理解和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()

它必须与范围(eval fails in list comprehension)有关。我对python 2(我刚刚移至python 3)范围的理解是,a不应在run()中定义,而a2是应该定义的。列表理解的影响使我更加困惑。我的期望是test2test3行应该失败,因为a没有用test方法定义。我还希望如果test5运行正常,那么test6test7也应该没问题。

仅当在函数内的列表理解中使用eval时,才会发生此错误...如果这三个元素中的任何一个都不存在,则没有错误。我的问题是为什么?我觉得我不太了解它,无法提出一个更好的问题。

1 个答案:

答案 0 :(得分:3)

  

我对python 2(我刚刚移至python 3)范围的理解是,不应在run()中定义a,而应在a2中定义a。

a中的a2run都是可见的。 a是在全局范围内定义的,因此在该文件的任何位置都可见。

  

我希望如果test5运行正常,那么test6和test7也应该没问题。

在3.X中,列表推导具有自己的范围。 test6列表理解可以访问三个范围:列表理解的范围,函数的范围和全局范围。因此它可以访问ia2a

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

在2.7中,列表推导没有得到自己的范围。它们与定义的函数具有相同的作用域。这说明了为什么您的代码在2.7中执行但不在3.X中执行。 IIRC,这是在2.7和3.X之间对示波器系统进行的唯一更改。 (如果不是,那么这是唯一与此场景有关的更改。)