如何在Python的while循环语句中使用迭代器

23

在Python中,是否可以在while循环中使用生成器或迭代器?例如,像这样:

i = iter(range(10))
while next(i):
    # your code
这样做的目的是将迭代构建到while循环语句中,使其类似于for循环,不同之处在于现在可以将其他逻辑加入while语句中。

这样做的目的是为了让while循环语句具有迭代功能,从而使其类似于for循环。与for循环的区别在于,您现在可以在while语句中添加其他逻辑:

i = iter(range(10))
while next(i) and {some other logic}:
    # your code

然后它变成了一个很好的for循环/while循环混合体。

有人知道如何实现这个吗?


必须使用while循环吗?for x in i是更自然的方式。 - user2390182
我猜你不会在 it = itertools.count(); while next(it): 上尝试你的想法。 - RomanPerekhrest
你能提供更多关于你使用情况的上下文吗? - Chris_Rands
你如何访问迭代器返回的值,因为你不存储它,只是获取该项并评估其布尔结果,那么在循环中应该怎么办,因为你无法访问从迭代器返回的项? - Chris Doyle
你需要阐述的是while循环的停止因素应该是什么。那么it = iter([True, False, 1, 0, 1]); while next(it): print('1')呢?给出的答案很简单,但你的确切意图是什么? - RomanPerekhrest
1
假如我们希望保持这个通用性,这就是为什么我没有指明具体的附加逻辑。这里的停止因素可以被假定为超过最后一次迭代,直到迭代器抛出异常。@RomanPerekhrest - Union find
5个回答

34

在 Python >= 3.8 中,您可以使用分配表达式执行以下操作:

i = iter(range(10))
while (x := next(i, None)) is not None and x < 5:
    print(x)

在 Python < 3.8 版本中,您可以使用 itertools.takewhile 函数:

from itertools import takewhile

i = iter(range(10))
for x in takewhile({some logic}, i):
    # do stuff

"一些逻辑"在这里将是一个接收 next(i) 产生的任何内容的1个参数可调用函数:

for x in takewhile(lambda e: 5 > e, i):
    print(x)
0
1
2
3
4

1
None 参数很重要,否则会抛出 stopIteration 异常。 - gabriel garcia
1
如果集合或流中的元素为None,怎么办? - xing
如果你的集合中有None元素,那么你想要执行next(i)并捕获StopIteration异常。 - Alexei Andreev
1
@AlexeiAndreev 你可以用任何不会在你的迭代器中出现的标记对象来替换 None - user2390182

12

while next(i, None):有两个问题:

  1. while循环不会像for循环一样捕获StopIteration异常,如果没有下一个值就会引发该异常。在这种情况下,可以使用next(i, None)返回一个“假值”,但是while循环也会在迭代器返回实际假值时停止。
  2. next返回的值将被消耗,在循环体中不再可用。 (在Python 3.8+中,可以通过赋值表达式来解决此问题,请参见其他答案)。

相反,您可以使用for循环和itertools.takewhile,测试可迭代对象的当前元素或任何其他条件。这将循环直到可迭代对象耗尽或条件评估为false。

from itertools import takewhile
i = iter(range(10))
r = 0
for x in takewhile(lambda x: r < 10, i):
    print("using", x)
    r += x
print("result", r)

输出:

using 0
...
using 4
result 10

1
所有的内容都被踩了...这似乎是一个非常合理的问题/答案。 - Union find

5

当迭代器到期时,您只需要安排它返回一个类似false的值即可。例如,如果我们将range反转,使其从大到小计数:

>>> i = iter(range(5, -1, -1))
>>> while val := next(i):
...     print('doing something here with value', val)
...

这将导致:
doing something here with value 5
doing something here with value 4
doing something here with value 3
doing something here with value 2
doing something here with value 1

2
但这会消耗 next(i),如果你在循环体中再次调用它,你会错过一个值。也许可以使用 Python 3.8 的赋值表达式来解决这个问题。 - tobias_k
当然,这将是一个使用赋值表达式非常理想的场合。从问题中并不清楚您是否关心迭代器的值。 - larsks
更新了示例以使用赋值表达式。 - larsks

2
a = iter(range(10))

try:
    next(a)
    while True:
        print(next(a))
except StopIteration:
    print("Stop iteration")

1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

-3

你可以做到

    a = iter(range(10))

    try:
        a.next()
        while True and {True or False logic}:
            print("Bonjour")
            a.next()
    except StopIteration:
        print("a.next() Stop iteration")

6
“while True and (True or False)”这句话是一个 Python 编程语言中的代码片段,它的意思是当条件为真时一直执行循环。这是一个常见的编程结构,不是一个笑话。 - Chris_Rands
@Chris_Rands 不,这是他[某些逻辑]的替代品。 - TOTO
这正是我不想做的。我想把下一个放在while语句中。 - Union find
1
知道了(不是我的设想),在Python 3中你也应该使用next(a) - Chris_Rands

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