什么是Python类中的列表理解范围规则?

发布于 2021-01-29 17:30:34

在以下代码中,该mc分配在Python 2和3中工作正常。

cc分配在类中使用相同的列表理解,在Python 2中有效,但在Python 3中失败。

是什么解释了这种行为?

ml1 = "a b c".split()
ml2 = "1 2 3".split()
mc = [ i1 + i2 for i1 in ml1 for i2 in ml2 ]

class Foo(object):
    cl1 = ml1
    cl2 = ml2

    cc1 = [ i1 for i1 in cl1 ]
    cc2 = [ i2 for i2 in cl2 ]
    cc = [ i1 + i2 for i1 in cl1 for i2 in cl2 ]


print("mc = ", mc)
foo = Foo()
print("cc = ", foo.cc)

我得到这个:

(default-3.5) snafu$ python2 /tmp/z.py 
('mc = ', ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3'])
('cc = ', ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3'])

(default-3.5) snafu$ python3 /tmp/z.py 
Traceback (most recent call last):
  File "/tmp/z.py", line 5, in <module>
    class Foo(object):
  File "/tmp/z.py", line 11, in Foo
    cc = [ i1 + i2 for i1 in cl1 for i2 in cl2 ]
  File "/tmp/z.py", line 11, in <listcomp>
    cc = [ i1 + i2 for i1 in cl1 for i2 in cl2 ]
NameError: name 'cl2' is not defined

为什么cl2没有定义类变量?请注意,cc2分配工作正常cc1。交换cl1cl2理解表明第二个循环是触发异常的循环,而不是cl2本身。)

版本:

(default-3.5) snafu$ python2 --version
Python 2.7.11+
(default-3.5) snafu$ python3 --version
Python 3.5.1+
关注者
0
被浏览
53
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    在Python 3中,列表推导具有自己的范围,该范围遵循与函数范围相同的规则。您知道类的方法不会自动在类范围内进行变量查找吗?

    class Example:
        var = 1
        def this_fails(self):
            print(var)
    Example().this_fails()  # NameError
    

    这适用于嵌套在类范围内的任何函数范围, 包括list comprehension的范围
    cl2在列表理解内的查找绕过了类范围,直接进入了全局变量。它的工作原理如下:

    class Foo(object):
        ...
        def make_cc(outer_iterable):
            result = []
            for i1 in outer_iterable:
                for i2 in cl2:  # This fails
                    result.append(i1 + i2)
            return result
        cc = make_cc(cl1)  # cl1 is evaluated outside the comprehension scope, for reasons
    

    请注意,cl1查找工作正常,因为尽管它在语法上嵌套在理解内,但它发生在理解之外的类范围内。当Python引入genexps时,他们就做出了这个决定,因为它早些时候捕获了一些常见的genexp错误。这也是为什么cc1andcc2列表理解有效的原因。它们唯一使用类级变量是在其外部(仅)for可迭代的。

    在类语句中使用理解和生成器表达式是一团糟。它不应该,但是应该。坚持常规循环,或在类语句之外运行理解,以便使语义更加明显。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看