Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 嵌套列表理解范围_Python_Python 3.x_Scope_Cpython - Fatal编程技术网

Python 嵌套列表理解范围

Python 嵌套列表理解范围,python,python-3.x,scope,cpython,Python,Python 3.x,Scope,Cpython,最好用一个例子来解释我的问题: example.py: class A(object): integers = [1, 2, 3] singles = [i for i in integers] class B(object): integers = [1, 2, 3] pairs = [(i, j) for i in integers for j in integers] 当我在Python2下运行它时,它运行得很好,但是在Python3下,我得到了类B的N

最好用一个例子来解释我的问题:

example.py:

class A(object):
    integers = [1, 2, 3]
    singles = [i for i in integers]

class B(object):
    integers = [1, 2, 3]
    pairs = [(i, j) for i in integers for j in integers]
当我在Python2下运行它时,它运行得很好,但是在Python3下,我得到了类
B
NameError
(但不是类
a
):

$python example.py
回溯(最近一次呼叫最后一次):
文件“example.py”,第6行,在
B类(对象):
文件“example.py”,B中第8行
pairs=[(i,j)表示整数中的i表示整数中的j]
文件“example.py”,第8行,在
pairs=[(i,j)表示整数中的i表示整数中的j]
NameError:未定义全局名称“整数”

为什么只有类
B
会引发
namererror
,为什么只有在Python3下才会发生?

类作用域在Python3中有点奇怪,但这是有充分理由的

在Python2中,迭代变量(
i
j
在您的示例中)从列表理解中泄漏出来,将包含在外部范围中。这是因为它们是在Python2设计的早期开发的,并且基于显式循环。作为一个意外的例子,请检查Python 2中未出现错误的
B.i
B.j
的值

在Python3中,更改了列表理解以防止这种泄漏。它们现在使用一个函数(有自己的作用域)实现,该函数被调用以生成列表值。这使得它们的工作原理与生成器表达式相同,生成器表达式一直是隐藏的函数

其结果是,在类中,列表理解通常看不到任何类变量。这与无法直接查看类变量的方法类似(仅通过
self
或显式类名)。例如,在下面的类中调用该方法将产生与列表中看到的相同的
namererror
异常:

class Foo:
    classvar = "bar"
    def blah(self):
        print(classvar) # raises "NameError: global name 'classvar' is not defined"
class C:
    num = 5
    products = [i * num for i in range(10)] # raises a NameError about num
但是,有一个例外:列表理解的第一个
for
子句迭代的序列在内部函数之外进行计算。这就是您的
A
类在Python3中工作的原因。它这样做是为了生成器可以立即捕获不可iterable对象(而不仅仅是在调用
next
并运行其代码时)

但是,它不适用于B类两级理解中的内部
for
子句

如果使用
dis
模块反汇编一些创建列表理解的函数,您可以看到不同之处:

def f(lst):
    return [i for i in lst]

def g(lst):
    return [(i, j) for i in lst for j in lst]
下面是对
f
的反汇编:

>>> dis.dis(f)
  2           0 LOAD_CONST               1 (<code object <listcomp> at 0x0000000003CCA1E0, file "<pyshell#374>", line 2>) 
              3 LOAD_CONST               2 ('f.<locals>.<listcomp>') 
              6 MAKE_FUNCTION            0 
              9 LOAD_FAST                0 (lst) 
             12 GET_ITER             
             13 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
             16 RETURN_VALUE       
这一次,它使用代码对象而不是基本函数构建闭包。闭包是一个带有一些“自由”变量的函数,这些变量引用封闭范围内的内容。对于
g
中的
函数,由于它的作用域是正常的,所以它可以正常工作。但是,当您尝试在类B中使用相同的理解时,闭包失败,因为类不允许它们包含的函数以这种方式进入它们的范围(如上面的
Foo
类所示)

值得注意的是,不仅内部序列值会导致此问题。正如BrenBarn在注释中链接到的一样,如果在列表的其他地方引用了类变量,则会出现相同的问题:

class Foo:
    classvar = "bar"
    def blah(self):
        print(classvar) # raises "NameError: global name 'classvar' is not defined"
class C:
    num = 5
    products = [i * num for i in range(10)] # raises a NameError about num
但是,在多级列表理解中,内部
for
(或
if
)子句只引用前面循环的结果时,不会出现错误。这是因为这些值不是闭包的一部分,只是
函数范围内的局部变量

class D:
    nested = [[1, 2, 3], [4, 5, 6]]
    flattened = [item for inner in nested for item in inner] # works!

就像我说的,类范围有点奇怪。

你确定吗@karthikr似乎与它是一个类变量这一事实有关:在Python3.3.2中测试可以正常工作。如果将
pairs=[(i,j)…等
替换为
pairs=list((i,j)for i in integers for j in integers)
,您应该会在2中看到相同的
NameError
。@BrenBarn,这个问题不太一样。也许错误在于我可以访问类A中的
integers
?我不太明白。如果“列表理解无法查看任何类变量",那么为什么我可以在类A中看到
整数
?是因为我在“调用”外部列表理解函数时可以访问整数,但不能在其主体内访问吗?@sn6uv:因为在理解的第一个
for
子句中迭代的对象是在外部范围中计算的,而不是在由理解函数创建的范围中计算的继续。如果你认为这很奇怪,那么你是对的。这种行为是为了帮助早期在生成器表达式中检测bug而做出的设计决策的结果。@sn6uv:Hmm,我似乎回答了问题的错误部分。我以为你问的问题与另一个问题相同,BrenBarn在顶级Common中作为副本链接t、 结果有点奇怪。我将编辑以更新。在Python 2中,迭代变量(在您的示例中为I和j)从列表理解中泄漏出来…---事实上,我刚刚发现了它。这太荒谬了!