【问题标题】:Looping from 1 to infinity in Python在 Python 中从 1 循环到无穷大
【发布时间】:2012-04-10 16:04:54
【问题描述】:

在 C 中,我会这样做:

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

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

【问题讨论】:

  • 我不是 python 专家,但 while (true): if reasonneeded(i) break i = i+1 应该可以吗?
  • python unbounded xrange()的可能重复
  • 在 C 中这会导致溢出而不是“无穷大”
  • 这个问题的标题不应该改成“Python中从0循环到无穷大”吗?你只是想拥有一个“无限的range”,所以你可以避免while True: i += 1

标签: python loops


【解决方案1】:

使用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()

【讨论】:

  • 这也与takewhile 配合得很好:for x in takewhile(thereIsAReasonToContinue, count()):
  • 对我来说,for i in range(sys.maxint)MemoryError 断开。您还提到了xrange(),它有效。
  • @scai,在 Python3 中 range 替换了 Python2 的 xrange。在 Python2 中,range 创建并返回一个实际的整数列表。这么大的列表你没有足够的内存
【解决方案2】:
def to_infinity():
    index = 0
    while True:
        yield index
        index += 1

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

【讨论】:

    【解决方案3】:

    最简单最好的:

    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。如果生成器是某个局部变量 i 的闭包,那么您也可以使用 takewhile 来模仿它们。在某种程度上,定义该闭包会特别明显地表明您正在做一些可能与您的控制结构混淆的事情。

      【讨论】:

        【解决方案5】:

        如果您想使用for 循环,可以将内置函数iter(另请参见this answer)和enumerate 组合成一个无限的for 循环,它有一个计数器。我们使用iter 创建无限迭代器,enumerate 提供计数循环变量。起始值默认为零,但您可以使用 start 参数设置不同的起始值。

        for i, _ in enumerate(iter(bool, True), start=1):
            input(i)
        

        哪些打印:

        1
        2
        3
        4
        5
        ...
        

        【讨论】:

          【解决方案6】:

          如果你在 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
          

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

          如果您的潜在退出是循环的开始处的一个简单退出(因为它似乎在这里),通常最好将退出编码到循环本身中。

          【讨论】:

            【解决方案7】:
            def infinity():
                i=0
                while True:
                    i+=1
                    yield i
            
            
            for i in infinity():
                if there_is_a_reason_to_break(i):
                    break
            

            【讨论】:

            • 谢谢,这正是我要找的。 imo 最干净和最好的方法。
            • 是的,非常干净,除了惰性序列生成器之外,我还没有完全了解 yield 的强大功能,但最近有一个朋友用它来提供 pushd/popd 函数,而无需维护显式堆栈。非常聪明,确实如此。
            • 虽然我喜欢这种方法,但无穷大现在是一个范围。如果你问我,零不是无穷大的一部分。哦,它是 this answer 的一个严重改写版本。
            【解决方案8】:
            def natural_numbers():
              yield from map(sum, enumerate(iter(int,1)))
            
            for i in natural_numbers():
              if there_is_a_reason_to_break(i):
                  break;
            

            【讨论】:

            • 此问题有 7 个现有答案,其中包括一个获得最多票数且获得超过 150 票 的答案。为什么您认为您的方法改进了已通过社区验证的现有提案?提供解释在 Stack Overflow 上总是 很有用,但在问题已得到解决且让 OP 和社区都满意的情况下,这一点尤其非常重要。通过解释您的答案的不同之处以及在什么情况下可能更受欢迎,帮助未来的读者。
            猜你喜欢
            • 2023-02-07
            • 1970-01-01
            • 2021-11-17
            • 1970-01-01
            • 2015-03-22
            • 2014-10-30
            • 1970-01-01
            • 2017-03-08
            • 1970-01-01
            相关资源
            最近更新 更多