Можно ли реализовать цикл Python для диапазона без переменной итератора?


можно ли сделать следующее без i?

for i in range(some_number):
    # do something

Если вы просто хотите сделать что-то N раз и не нуждаетесь в итераторе.

15 146

15 ответов:

С моей головы, нет.

Я думаю, лучшее, что вы могли бы сделать что-то вроде этого:

def loop(f,n):
    for i in xrange(n): f()

loop(lambda: <insert expression here>, 5)

но я думаю, что вы можете просто жить с лишним i переменной.

вот возможность использовать _ переменная, которая на самом деле является просто еще одной переменной.

for _ in range(n):
    do_something()

отметим, что _ присваивается последний результат, который возвращается в интерактивном сеансе python:

>>> 1+2
3
>>> _
3

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

>>> for _ in xrange(10): pass
...
>>> _
9
>>> 1+2
3
>>> _
9

и по питон грамматики, это допустимое имя переменной:

identifier ::= (letter|"_") (letter | digit | "_")*

Вы можете искать

for _ in itertools.repeat(None, times): ...

Это самый быстрый способ итерации times раз в Python.

общая идиома для присвоения значения, которое не используется, - это назвать его _.

for _ in range(times):
    do_stuff()

то, что все предлагают вам использовать _ не говорит, что _ часто используется в качестве ярлыка для одного из gettext функции, так что если вы хотите, чтобы ваше программное обеспечение было доступно на нескольких языках, то вам лучше избегать его использования для других целей.

import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print _('This is a translatable string.')

вот случайная идея, которая использует (злоупотребления?) в модель данных ( Py3 link).

class Counter(object):
    def __init__(self, val):
        self.val = val

    def __nonzero__(self):
        self.val -= 1
        return self.val >= 0
    __bool__ = __nonzero__  # Alias to Py3 name to make code work unchanged on Py2 and Py3

x = Counter(5)
while x:
    # Do something
    pass

интересно, есть ли что-то подобное в стандартных библиотеках?

вы можете использовать _11 (или любое число или другой недопустимый идентификатор), чтобы предотвратить name-colision с gettext. Каждый раз, когда вы используете подчеркивание + недопустимый идентификатор, вы получаете фиктивное имя, которое можно использовать в цикле for.

может быть ответ будет зависеть от того, какая проблема у вас есть с использованием итератора? можно использовать

i = 100
while i:
    print i
    i-=1

или

def loop(N, doSomething):
    if not N:
        return
    print doSomething(N)
    loop(N-1, doSomething)

loop(100, lambda a:a)

но, честно говоря, я не вижу смысла в использовании таких подходов

t=0    
for _ in range(10):
    print t
    t = t+1

выход:

0
1 
2 
3 
4 
5 
6 
7
8
9

Я в целом согласен с решениями, приведенными выше. А именно:

  1. использование подчеркивания в for - цикл (2 и более строк)
  2. определение нормального while счетчик (3 и более строк)
  3. объявление пользовательского класса с помощью __nonzero__ реализация (много строк)

если нужно определить объект как в #3 я бы рекомендовал реализовать протокол для С ключевое слово или применить contextlib.

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

from itertools import (chain, repeat)

times = chain(repeat(True, 2), repeat(False))
while next(times):
    print 'do stuff!'

в этом примере 2 - это количество раз, чтобы повторить цикл. цепи оборачивает два повторить итераторы, первый из которых ограничен, но второй бесконечен. Помните, что это истинный итератор объекты, следовательно, они не требуют бесконечной памяти. Очевидно, что это намного медленнее, чем решение #1. Если не написано как часть функции, это может потребовать очистки для времени переменной.

мы повеселились со следующим, интересно поделиться так:

class RepeatFunction:
    def __init__(self,n=1): self.n = n
    def __call__(self,Func):
        for i in xrange(self.n):
            Func()
        return Func


#----usage
k = 0

@RepeatFunction(7)                       #decorator for repeating function
def Job():
    global k
    print k
    k += 1

print '---------'
Job()

результаты:

0
1
2
3
4
5
6
---------
7

если do_something - Это простая функция или может быть обернут в один, простой map() можете do_somethingrange(some_number) раза:

# Py2 version - map is eager, so it can be used alone
map(do_something, xrange(some_number))

# Py3 version - map is lazy, so it must be consumed to do the work at all;
# wrapping in list() would be equivalent to Py2, but if you don't use the return
# value, it's wastefully creating a temporary, possibly huge, list of junk.
# collections.deque with maxlen 0 can efficiently run a generator to exhaustion without
# storing any of the results; the itertools consume recipe uses it for that purpose.
from collections import deque

deque(map(do_something, range(some_number)), 0)

если вы хотите передать аргументы в do_something, вы также можете найти itertools repeatfunc рецепт читает так:

чтобы передать те же аргументы:

from collections import deque
from itertools import repeat, starmap

args = (..., my args here, ...)

# Same as Py3 map above, you must consume starmap (it's a lazy generator, even on Py2)
deque(starmap(do_something, repeat(args, some_number)), 0)

для передачи различных аргументов:

argses = [(1, 2), (3, 4), ...]

deque(starmap(do_something, argses), 0)

вместо ненужного счетчика, теперь у вас есть ненужный список. Лучшим решением является использование переменной, которая начинается с"_", которая сообщает синтаксическим шашкам, что вы знаете, что не используете переменную.

x = range(5)
while x:
  x.pop()
  print "Work!"

Если вы действительно хотите избежать размещения чего-то с именем (либо переменная итерации, как в OP, либо нежелательный список или нежелательный генератор, возвращающий true нужное количество времени), вы можете сделать это, если действительно хотите:

for type('', (), {}).x in range(somenumber):
    dosomething()

трюк, который используется, чтобы создать анонимный класс type('', (), {}) что приводит к классу с пустым именем, но NB, что он не вставляется в локальное или глобальное пространство имен (даже если было указано непустое имя). Затем вы используете член этого класса как переменная итерации, которая недоступна, так как класс, в котором она является членом, недоступен.

#Return first n items of the iterable as a list
list(itertools.islice(iterable, n))

взято из http://docs.python.org/2/library/itertools.html

о:

while range(some_number):
    #do something