在返回语句中使用for循环
我在研究Nosklo在如何以块的方式遍历列表的最“Pythonic”方法?中的回答,他定义了一个函数:
def chunker(seq, size):
return (seq[pos:pos + size] for pos in xrange(0, len(seq), size))
有人能解释一下当return后面跟着for循环时是怎么回事吗?我尝试做了以下事情:
def chunker2(seq, size):
for pos in xrange(0, len(seq), size):
return seq[pos:pos + size]
但我得不到相同的结果。注意在Nosklo的例子中,chunker()
是像下面的例子那样被逐步调用的:
animals = ['cat', 'dog', 'rabbit', 'duck', 'bird', 'cow', 'gnu', 'fish']
for group in chunker(animals, 3):
print group
通过添加打印语句,我注意到后面的for
循环执行了3次(它遍历了animals
列表),但在chunker
函数中的for循环只执行了一次。那么,为什么只有一个return,我却能看到3个打印输出呢?
1 个回答
3
nosklo的chunker
函数返回的值叫做生成器,这是一种在被遍历时会生成值的对象。在这个例子中,生成器是通过一个叫做生成器表达式创建的,这个表达式就是括号里的那段代码:(seq[pos:pos + size] for pos in xrange(0, len(seq), size))
。
>>> def chunker(seq, size):
... return (seq[pos:pos + size] for pos in xrange(0, len(seq), size))
...
>>> result = chunker([1, 2, 3], 2)
>>> print(result)
<generator object <genexpr> at 0x10581e1e0>
>>> next(result)
[1, 2]
>>> next(result)
[3]
关于调用的内容,我们可以把循环的代码改写成这样,以便更清楚地理解:
>>> generator = chunker(animals, 3)
>>> for chunk in generator:
... print chunk
...
['cat', 'dog', 'rabbit']
['duck', 'bird', 'cow']
['gnu', 'fish']
chunker
函数只被调用了一次,返回一个生成器对象,我们把它存储在generator
变量中。接下来的for
循环只是在这个generator
对象上工作,并且调用了它3次。
如果你想打印出这个生成器的实际调用,你需要把print
语句放在生成器表达式(seq[pos:pos + size] for pos in xrange(0, len(seq), size))
里面,但这是不允许的。不过,我们可以把这个生成器表达式改写成一个普通的生成器函数,使用yield
语句,这种方式更详细,也更灵活,我们可以在里面加入print
语句,这样就能按照你最初的预期工作了:
>>> def chunker2(seq, size):
... for pos in xrange(0, len(seq), size):
... print('chunker2 generator called')
... yield seq[pos:pos + size]
...
>>> for group in chunker2(animals, 3):
... print group
...
chunker2 generator called
['cat', 'dog', 'rabbit']
chunker2 generator called
['duck', 'bird', 'cow']
chunker2 generator called
['gnu', 'fish']
在这里,chunker2
函数本身就是实际的生成器,并且被调用了3次。