在Python中从1循环到无穷大


80

在C语言中,我会这样做:

int i;
for (i = 0;; i++)
  if (thereIsAReasonToBreak(i))
    break;

如何在Python中实现类似的功能?


2
我不是python专家,但while (true): if reasonneeded(i) break i = i+1应该可以吗?
HKF 2012年


在C语言中,这将导致溢出,而​​不会变为“无穷大”
Philipp

1
是否应该将此问题的标题更改为“在Python中从0循环到无穷大”?您只是想拥有一个“无限range”,所以您可以避免while True: i += 1
SomethingSomething

Answers:


141

使用itertools.count

import itertools
for i in itertools.count(start=1):
    if there_is_a_reason_to_break(i):
        break

在Python 2,range()xrange()仅限于sys.maxsize。在Python 3中range()可以更高,尽管不能达到无穷大:

import sys
for i in range(sys.maxsize**10):  # you could go even higher if you really want
    if there_is_a_reason_to_break(i):
        break

因此,最好使用count()


10
这也可以很好地发挥作用takewhilefor x in takewhile(thereIsAReasonToContinue, count()):
乔治

对我而言,以for i in range(sys.maxint)分隔MemoryError。您还提到了xrange()哪个有效。
scai

3
@scai,在Python3中range替换了Python2的xrange。在Python2中,range创建并返回一个实际的int列表。您将没有足够的内存来容纳这么大的列表
John La Rooy

18
def to_infinity():
    index = 0
    while True:
        yield index
        index += 1

for i in to_infinity():
    if i > 10:
        break

9

最简单,最好:

i = 0
while not there_is_reason_to_break(i):
    # some code here
    i += 1

选择与Python中C代码最接近的类比可能很诱人:

from itertools import count

for i in count():
    if thereIsAReasonToBreak(i):
        break

但是要注意,修改i不会像在C中那样影响循环的流程。因此,使用while循环实际上是将C代码移植到Python的更合适的选择。


4

重申thg435的评论:

from itertools import takewhile, count

def thereIsAReasonToContinue(i):
    return not thereIsAReasonToBreak(i)

for i in takewhile(thereIsAReasonToContinue, count()):
    pass # or something else

或更简洁地说:

from itertools import takewhile, count

for i in takewhile(lambda x : not thereIsAReasonToBreak(x), count()):
    pass # or something else

takewhile模仿“行为良好”的C for循环:您有一个延续条件,但有一个生成器而不是一个任意表达式。您可以在C for循环中执行“行为不佳”的事情,例如i在循环主体中进行修改。takewhile如果生成器是某个局部变量的闭包i,那么您也可以使用来模仿它们。从某种意义上说,定义闭包可以使您特别明显地发现您正在做的事情可能会使您的控制结构混乱。


2
def infinity():
    i=0
    while True:
        i+=1
        yield i


for i in infinity():
    if there_is_a_reason_to_break(i):
        break

1
谢谢,这就是我想要的。最干净和最好的方法imo。
Marcel Braasch

是的,非常干净,yield除了懒惰序列生成器之外,我没有其他功能,但是最近一个朋友使用它来提供pushd/popd函数,而不必维护显式堆栈。非常聪明。
paxdiablo

2

如果您在C语言中执行此操作,那么您的判断就会像在Python中一样模糊:-)

对于在每次迭代开始时通过简单条件检查退出的循环,仅在循环结构本身中执行此操作(在我看来更清楚)。换句话说,就像(如果您需要i在循环结束之后):

int i = 0;
while (! thereIsAReasonToBreak(i)) {
    // do something
    i++;
}

或(如果i可以限制为循环):

for (int i = 0; ! thereIsAReasonToBreak(i); ++i) {
    // do something
}

那将转化为等效的Python:

i = 0
while not there_is_a_reason_to_break(i):
    # do something
    i += 1

只有当您需要在循环中间的某个位置退出(或者您的条件足够复杂以至于使循环语句的可读性大大降低)时,您才需要担心中断。

如果您的潜在退出在循环开始时只是一个简单的出口(如此处所示),通常最好将出口编码到循环本身中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.