Питоновское перечисление цикла while

Python имеет элегантный способ автоматического создания переменной счетчика for циклов: функция enumerate . Это экономит необходимость инициализации и увеличения переменной счетчика. Счетные переменные также уродливы, потому что они часто бесполезны после завершения цикла, но их область действия не является сферой цикла, поэтому они не занимают пространство имен (хотя я не уверен, действительно ли это enumerate ).

Мой вопрос в том, есть ли подобное питоновское решение для циклов while . enumerate не будет работать для циклов while так как enumerate возвращает итератор. В идеале решение должно быть «pythonic» и не требует определения функций.

Например:

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

В этом случае мы хотели бы избежать инициализации и увеличения c .

Разъяснение:

Это может быть сделано с бесконечным циклом с ручным завершением, как некоторые предложили, но я ищу решение, которое делает код более четким, и я не думаю, что это решение делает код более понятным в этом случае.

Улучшение (в читабельности, я бы сказал) к ответу Игнасио:

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

Преимущества:

  • Только условие цикла while находится в заголовке цикла, а не в побочном эффекте raw_input.
  • Условие цикла может зависеть от любого условия, которое может иметь нормальный цикл while. Нет необходимости «импортировать» переменные, указанные в таблице, так как они уже видны в области лямбда. Кроме того, он может зависеть от счета, если вы хотите, хотя и не в этом случае.
  • Упрощен: перечисление больше не отображается.

Опять с 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 

Если вы хотите инициализацию нуля до цикла 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) 

Я не думаю, что вы можете делать то, что хотите, точно так, как хотите. Если я правильно понимаю, вам нужен цикл while, который каждый раз увеличивает счетчик, не выставляя видимый счетчик за пределы цикла. Я думаю, что способ сделать это – переписать цикл while как цикл без прерывания и проверить состояние конца вручную. Для вашего примера кода:

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

Проблема в том, что в основном вы делаете итерацию с помощью счетчика. Если вы не хотите выставлять этот счетчик, он должен исходить из конструкции цикла. Без определения новой функции вы застряли со стандартным циклом и явной проверкой.

С другой стороны, вы могли бы, вероятно, также определить генератор для этого. Вы все равно будете выполнять итерацию, но вы можете по крайней мере обернуть проверку в контуре цикла.