9

forPython 有一种优雅的方式在循环中自动生成计数器变量:enumerate函数。这省去了初始化和递增计数器变量的需要。计数器变量也很丑,因为它们通常在循环结束后就没用了,但它们的范围不是循环的范围,所以它们不需要占用命名空间(虽然我不确定是否enumerate真的解决了这个问题)。

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

例如:

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

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

澄清:

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

4

4 回答 4

9

对伊格纳西奥的回答进行了改进(我想说的是可读性):

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 范围内可见。此外,如果您愿意,它可以取决于计数,但在这种情况下并非如此。
  • 简化:枚举不再出现。
于 2013-06-16T21:22:26.987 回答
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
于 2013-06-16T21:12:36.723 回答
2

如果您想在循环之前进行初始化,您可以使用带计数器的Singleton :while

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,则可以子类化一个 interator:

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)
于 2013-06-16T21:18:15.033 回答
1

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

import itertools

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

问题在于,从根本上讲,您正在使用计数器进行迭代。如果您不想公开该计数器,则它需要来自循环构造。如果不定义新函数,您将陷入标准循环和显式检查。

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

于 2013-06-16T20:52:51.573 回答