Pythonic枚举while循环

时间:2013-06-16 20:39:55

标签: python while-loop

Python有一种在for循环中自动生成计数器变量的优雅方式:enumerate函数。这节省了初始化和递增计数器变量的需要。计数器变量也很难看,因为它们在循环完成后通常是无用的,但它们的范围不是循环的范围,因此它们不需要占用命名空间(尽管我不确定enumerate是否实际解决了这个问题)

我的问题是,while循环是否存在类似的pythonic解决方案。由于enumerate返回迭代器,while将不适用于enumerate循环。理想情况下,解决方案应该是“pythonic”,不需要函数定义。

例如:

x=0
c=0
while x<10:
  x=int(raw_input())
  print x,c
  c+=1

在这种情况下,我们希望避免初始化和递增c

澄清:

这可以通过手动终止的无限for循环来完成,正如一些人所建议的那样,但我正在寻找一种能让代码更清晰的解决方案,我认为这个解决方案不会让代码更清晰这种情况。

4 个答案:

答案 0 :(得分:7)

Ignacio的答案改进(可读性,我会说):

x = 0
for c in itertools.takewhile(lambda c: x < 10, itertools.count()):
    x = int(raw_input())
    print x, c

优点:

  • 只有while循环条件在循环标题中,而不是副作用raw_input。
  • 循环条件可以取决于正常while循环可以的任何条件。没有必要“导入”引用到takewhile中的变量,因为它们已经在lambda范围中可见。此外,如果您愿意,它可以取决于计数,但不是在这种情况下。
  • 简化:枚举不再出现。

答案 1 :(得分:6)

再次使用itertools ...

import itertools

for c, x in enumerate(
    itertools.takewhile(lambda v: v < 10,
      (int(raw_input()) for z in itertools.count())
    )
  ):
  print c, x

答案 2 :(得分:2)

如果您想在while循环之前初始化,则可以将Singleton与计数器一起使用:

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(
                                cls, *args, **kwargs)
            cls.count=0
        else:
            cls.count+=1                            
        return cls._instance

然后只有一个Singleton实例,每个附加实例只添加一个:

>>> Singleton().count    # initial instance
0
>>> Singleton().count
1
>>> Singleton().count
2
>>> Singleton().count
3

然后你的while循环变为:

while Singleton():
    x=int(raw_input('x: '))
    if x>10: break

print 'While loop executed',Singleton().count,'times' 

输入1,2,3,11打印:

x: 1
x: 2
x: 3
x: 11
While loop executed 4 times

如果您不介意在while循环之前进行单行初始化,则可以只对子函数进行子类化:

import collections
class WhileEnum(collections.Iterator):
    def __init__(self,stop=None):
        self.stop=stop
        self.count=0

    def next(self):    # '__next__' on Py 3, 'next' on Py 2
        if self.stop is not None:
            self.remaining=self.stop-self.count
            if self.count>=self.stop: return False
        self.count+=1    
        return True

    def __call__(self):
        return self.next()

然后你的while循环变为:

enu=WhileEnum()
while enu():
    i=int(raw_input('x: '))
    if i>10: break

print enu.count

我认为第二种方法是更好的方法。您可以拥有多个枚举器,还可以设置限制循环次数:

limited_enum=WhileEnum(5)

答案 3 :(得分:1)

我认为不可能按照你想要的方式做你想做的事。如果我理解正确,你需要一个while循环,每次循环增加一个计数器,而不实际暴露循环范围之外的可见计数器。我认为这样做的方法是将while循环重写为非终止for循环,并手动检查结束条件。对于您的示例代码:

import itertools

x = 0
for c in itertools.count():
    x = int(raw_input())
    print x, c
    if x >= 10:
        break

问题在于,从根本上说,你正在使用计数器进行迭代。如果您不想公开该计数器,则需要来自循环结构。在没有定义新功能的情况下,您会遇到标准循环和显式检查。

另一方面,你也可以为此定义一个生成器。你仍然在迭代,但你至少可以将检查包装在循环结构中。