如何使用Python从列表中yield所有的值?

64

假设我有一个列表,希望不返回整个列表,而是从中生成值。最符合Pythonic风格的方法是什么?

这就是我的意思。由于一些非惰性计算,我已经计算出了列表['a','b','c','d'],但是我的项目代码使用了惰性计算,因此我想从我的函数中生成值,而不是返回整个列表。

目前我已经将它写成以下形式:

my_list = ['a', 'b', 'c', 'd']
for item in my_list:
    yield item

但这种写法对我来说不太符合Python的编程风格。


3
为什么需要这样做呢?你可以使用“for x in container”的语法,其中 container 是列表或迭代器。无论类型如何,语法都不会改变,那么它是列表还是迭代器有什么关系呢?你仍然需要持续访问列表以从中产生结果,所以只需传递列表即可。 - Michael Aaron Safyan
旁注:由于首字母大写(参见PEP 8),许多人会认为“List”是一个类名。您可以使用“list_”或“my_list”等名称。 - Eric O. Lebigot
EOL,我感谢你的评论。谢谢。 - bodacydo
一个可迭代对象可以看作是它自己的生成器。也就是说,如果我能够写出 for i in my_iterable: 这样的代码,那么它会像一个生成器一样遍历并输出结果。 - msw
3个回答

94

由于这个问题没有具体说明,我将提供一个适用于Python >= 3.3的答案。

如果你只需要返回那个列表,请按照Anurag建议的方式操作,但是如果出于某些原因,所需函数确实需要成为生成器,那么可以委托给另一个生成器;假设你想给结果列表添加后缀,但只有在列表首次耗尽时才添加。

def foo():
    list_ = ['a', 'b', 'c', 'd']
    yield from list_

    if something:
        yield this
        yield that
        yield something_else

在Python 3.3之前的版本中,你不能使用这个语法;你需要使用问题中的代码,包含一个for循环和单个yield语句。或者,你可以将生成器包装在一个常规函数中,并返回chained结果:这也有在Python 2和3中工作的优点。
from itertools import chain

def foo():
    list_ = ['a', 'b', 'c', 'd']

    def _foo_suffix():
        if something:
            yield this
            yield that
            yield something_else

    return chain(list_, _foo_suffix())

33
“yield from list_”功能是一种很好的语法,这也是我来到这里想找的。可惜我不能在2.7中使用它。 - Mark Amery

40

使用 iter 创建一个列表迭代器,例如:

return iter(List)

如果你已经有一个列表,直接返回该列表会更有效率。


好问题。我没有答案。我将返回整个列表。我只是认为返回一个生成器是一个好主意,因为项目中的所有内容都使用生成器(除了这个地方 - 我从一个不懒惰的库中获取这个列表)。 - bodacydo
5
调用iter是完全多余的,这是过度设计。 - msw
4
iter虽然有些过度,但并非完全冗余。它可以用于记住在迭代列表时你的位置,并将其传递下去。使用列表时,你还需要传递一个索引值。 - Anurag Uniyal
11
@Anurag - 这似乎没有回答问题:如果我不想在那个点返回,我想从列表中产出所有东西,然后继续(可能会产出更多的东西)怎么办?这是相当普遍的情况(例如,遍历递归结构时),而且像bodacydo一样,我认为“for x in list yield x”解决方案不符合Pythonic。 - Edmund
@ Edmund 的答案针对问题 OP 提出的具体情况,并且他已将其作为答案接受。你提出的建议并不符合他的需求,也许你可以提出一个独立的问题。 - Anurag Uniyal

1
您可以通过以下方式构建生成器:
(x for x in List)

我可以这样做吗:return (x for x in list) - bodacydo
3
好的,但我不认为这会节省你太多的精力,因为你已经计算出了整个列表,那为什么不直接返回它呢? - Johannes Charra
8
内置函数iter()可以为你完成这个操作:不需要使用生成器表达式,后者的劣势在于速度较慢。 - Eric O. Lebigot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接