在返回语句中使用for循环

4 投票
1 回答
3959 浏览
提问于 2025-04-18 10:39

我在研究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次。

撰写回答