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))