Чи можна зробити наступне без i
?
for i in range(some_number):
# do something
Якщо ви просто хочете зробити щось N кількість разів і не потрібен ітератор.
Чи можна зробити наступне без i
?
for i in range(some_number):
# do something
Якщо ви просто хочете зробити щось N кількість разів і не потрібен ітератор.
Відповіді:
Зверху моєї голови, ні.
Я думаю, що найкраще ви могли зробити щось подібне:
def loop(f,n):
for i in xrange(n): f()
loop(lambda: <insert expression here>, 5)
Але я думаю, що ви можете просто жити з додатковою i
змінною.
Тут є можливість використовувати _
змінну, яка насправді є лише іншою змінною.
for _ in range(n):
do_something()
Зауважте, що _
присвоюється останній результат, який повернувся в інтерактивному сеансі пітона:
>>> 1+2
3
>>> _
3
З цієї причини я б не використовував це таким чином. Я не знаю жодної ідіоми, про яку згадував Райан. Це може зіпсувати ваш перекладач.
>>> for _ in xrange(10): pass
...
>>> _
9
>>> 1+2
3
>>> _
9
Відповідно до граматики Python , це прийнятна назва змінної:
identifier ::= (letter|"_") (letter | digit | "_")*
_
дає зрозуміти, що його слід ігнорувати. Сказати, що робити це не має сенсу, як сказати, що немає сенсу коментувати свій код - адже це все одно зробить саме те саме.
Ви можете шукати
for _ in itertools.repeat(None, times): ...
це найшвидший спосіб повторити times
час на Python.
Що всі, хто пропонує вам використовувати _, не говорять про те, що _ часто використовується як ярлик до однієї з функцій gettext , тому, якщо ви хочете, щоб ваше програмне забезпечення було доступне більш ніж однією мовою, тоді вам краще уникати його використання. для інших цілей.
import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print _('This is a translatable string.')
_
здається жахливою ідеєю, я б не проти конфліктувати з нею.
Ось випадкова ідея, яка використовує (зловживає?) Модель даних ( посилання Py3 ).
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
Цікаво, чи є щось подібне в стандартних бібліотеках?
__nonzero__
побічні ефекти, - жахлива ідея.
__call__
замість цього. while x():
не так важче написати.
Counter
; звичайно, це не зарезервовано або у вбудованій області, але collections.Counter
це річ , а створення однойменного класу ризикує заплутатися у підтримці (не те, що це вже не ризикує).
Ви можете використовувати _11 (або будь-яке число або інший недійсний ідентифікатор), щоб запобігти зіткненню імен з gettext. Щоразу, коли ви використовуєте підкреслювач + недійсний ідентифікатор, ви отримуєте фіктивне ім'я, яке можна використовувати для циклу.
Можливо, відповідь залежатиме від того, яка проблема у вас із використанням ітератора? може бути корисним
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)
але відверто кажучи, я не бачу сенсу використовувати такі підходи
sys.getrecursionlimit()
(що за замовчуванням десь у низькій четвірку) діапазон цифр на CPython); використання sys.setrecursionlimit
може підняти ліміт, але в кінцевому підсумку ви досягнете ліміту стека C, і інтерпретатор загине при переповненні стека (не просто піднявши приємне RuntimeError
/ RecursionError
).
t=0
for _ in range(10):
print t
t = t+1
ВИХІД:
0
1
2
3
4
5
6
7
8
9
Замість зайвого лічильника тепер у вас є непотрібний список. Найкращим рішенням є використання змінної, яка починається з "_", яка повідомляє перевіряючим синтаксисам, що вам відомо, що ви не використовуєте змінну.
x = range(5)
while x:
x.pop()
print "Work!"
Я загалом згоден з рішеннями, наведеними вище. А саме з:
for
-loop (2 та більше рядків)while
лічильника (3 і більше рядків)__nonzero__
реалізацією (ще багато рядків)Якщо потрібно визначити об'єкт як у №3, я б рекомендував реалізувати протокол для за допомогою ключового слова або застосувати контекстний зв'язок .
Далі пропоную ще одне рішення. Це 3 вкладиші і не має вищої елегантності, але він використовує пакет itertools і, таким чином, може представляти інтерес.
from itertools import (chain, repeat)
times = chain(repeat(True, 2), repeat(False))
while next(times):
print 'do stuff!'
У цьому прикладі 2 - кількість разів повторити цикл. ланцюг обгортає два повторювані ітератори, перший обмежений, але другий нескінченний. Пам'ятайте, що це справжні ітераторські об'єкти, отже, їм не потрібна нескінченна пам'ять. Очевидно, це набагато повільніше, ніж рішення №1 . Якщо записано як частину функції, це може потребувати очищення змінної часу .
chain
зайвий, times = repeat(True, 2); while next(times, False):
робить те ж саме.
Ми повеселилися наступним, цікавим поділитися таким чином:
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_something
range(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)
Якщо ви дійсно хочете уникати введення чого-небудь з іменем (або змінної ітерації, як в ОП, або небажаного списку, або небажаного генератора, що повертає справжню потрібну кількість часу), ви можете зробити це, якщо ви дійсно хотіли:
for type('', (), {}).x in range(somenumber):
dosomething()
Використовуваний трюк полягає у створенні анонімного класу, type('', (), {})
який приводить до класу з порожнім іменем, але зауважте, що він не вставляється у локальну чи глобальну область імен (навіть якщо введено непусте ім'я). Потім ви використовуєте член цього класу як змінну ітерації, яка недосяжна, оскільки клас, до якого він входить, недоступний.
#Return first n items of the iterable as a list
list(itertools.islice(iterable, n))
А як на рахунок:
while range(some_number):
#do something
range(some_number)
завжди справжня!
some_number
менше або дорівнює 0
, це не нескінченно, воно просто ніколи не працює. :-) І це неефективно для нескінченного циклу (особливо на Py2), оскільки він створює свіжий list
(Py2) або range
об'єкт (Py3) для кожного тесту (це не константа з точки зору перекладача, він повинен завантажувати range
і some_number
кожен цикл, зателефонуйте range
, а потім протестуйте результат).