Python:高级嵌套列表理解语法
我在玩弄列表parsing,以便更好地理解它们,并遇到了一些我无法解释的意外输出。 我以前没有find这个问题,但如果是/重复的问题,我很抱歉。
我本质上是试图写一个生成发电机的发电机。 使用列表理解的简单生成器将如下所示:
(x for x in range(10) if x%2==0) # generates all even integers in range(10) 我试图做的是写一个生成器生成两个生成器 – 其中第一个生成范围(10)的偶数,第二个生成范围(10)的奇数。 为此,我做了:
 >>> (x for x in range(10) if x%2==i for i in range(2)) <generator object <genexpr> at 0x7f6b90948f00> >>> for i in g.next(): print i ... Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <genexpr> UnboundLocalError: local variable 'i' referenced before assignment >>> g.next() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>> g = (x for x in range(10) if x%2==i for i in range(2)) >>> g <generator object <genexpr> at 0x7f6b90969730> >>> g.next() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <genexpr> UnboundLocalError: local variable 'i' referenced before assignment 
我不明白为什么“我”在分配之前被引用
 我认为这可能与i in range(2) ,所以我做了: 
 >>> g = (x for x in range(10) if x%2==i for i in [0.1]) >>> g <generator object <genexpr> at 0x7f6b90948f00> >>> g.next() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <genexpr> UnboundLocalError: local variable 'i' referenced before assignment 
这对我来说没有意义,所以我认为最好先尝试一些简单的方法。 所以我回到列表并尝试:
 >>> [x for x in range(10) if x%2==i for i in range(2)] [1, 1, 3, 3, 5, 5, 7, 7, 9, 9] 
我期望的是一样的:
 >>> l = [] >>> for i in range(2): ... for x in range(10): ... if x%2==i: ... l.append(x) ... >>> l [0, 2, 4, 6, 8, 1, 3, 5, 7, 9] # so where is my list comprehension malformed? 
但是,当我尝试了一下预感,这工作:
 >>> [[x for x in range(10) if x%2==i] for i in range(2)] [[0, 2, 4, 6, 8], [1, 3, 5, 7, 9]] # so nested lists in nested list comprehension somehow affect the scope of if statements? :S 
 所以我认为这可能是一个问题,什么级别的范围的if语句运作。所以我试过这个: 
 >>> [x for x in range(10) for i in range(2) if x%2==i] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
 而现在我彻底困惑。 有人可以解释这种行为。 我不明白为什么我的列表理解似乎是错误的,我也不理解if语句的范围如何工作。 
任何帮助将不胜感激
谢谢
PS:在certificate这个问题的同时,我意识到这看起来有点像一个家庭作业问题 – 事实并非如此。
你需要使用一些括号:
 ((x for x in range(10) if x%2==i) for i in range(2)) 
这对我来说没有意义,所以我认为最好先尝试一些简单的方法。 所以我回到列表并尝试:
[>>> [x for range(10)if x%2 == i for i in range(2)] [1,1,3,3,5,5,7,7,9,9]
这是因为之前的列表理解将ivariables泄漏到封闭范围,并成为当前的ivariables。 尝试启动一个新鲜的Python解释器,这将由于NameError失败。 在Python 3中,计数器的泄漏行为已被删除。
编辑:
等价的循环:
 (x for x in range(10) if x%2==i for i in range(2)) 
将会:
 l = [] for x in range(10): if x%2 == i: for i in range(2): l.append(x) 
这也给名称错误。
EDIT2:
括号版本:
 ((x for x in range(10) if x%2==i) for i in range(2)) 
相当于:
 li = [] for i in range(2): lx = [] for x in range(10): if x%2==i: lx.append(x) li.append(lx) 
Lie Rean的回答稍微扩展了一下:
something =(x for x in range(10)if x%2 == i for i in range(2))
相当于:
 def _gen1(): for x in range(10): if x%2 == i: for i in range(2): yield x something = _gen1() 
而括号版本相当于:
 def _gen1(): def _gen2(): for x in range(10): if x%2 == i: yield x for i in range(2): yield _gen2() something = _gen1() 
这实际上产生了两个发电机:
 [<generator object <genexpr> at 0x02A0A968>, <generator object <genexpr> at 0x02A0A990>] 
不幸的是,它产生的发电机有点不稳定,因为输出取决于你如何消耗它们:
 >>> gens = ((x for x in range(10) if x%2==i) for i in range(2)) >>> for g in gens: print(list(g)) [0, 2, 4, 6, 8] [1, 3, 5, 7, 9] >>> gens = ((x for x in range(10) if x%2==i) for i in range(2)) >>> for g in list(gens): print(list(g)) [1, 3, 5, 7, 9] [1, 3, 5, 7, 9] 
 我的build议是完整地写出生成器函数:我认为试图在没有这样做的情况下对i进行正确的作用域可能几乎是不可能的。 
Lie Ryan的for循环等价物引导我进入下面,这似乎工作得很好:
 [x for i in range(2) for x in range(10) if i == x%2] 
输出
 [0, 2, 4, 6, 8, 1, 3, 5, 7, 9] 
李对语法问题有答案。 一个build议:不要把太多东西塞进发电机的身体里。 一个函数更可读。
 def make_generator(modulus): return (x for x in range(10) if x % 2 == modulus) g = (make_generator(i) for i in range(2))