Czy można wykonać następujące czynności bez i
?
for i in range(some_number):
# do something
Jeśli chcesz po prostu zrobić coś N razy i nie potrzebujesz iteratora.
Czy można wykonać następujące czynności bez i
?
for i in range(some_number):
# do something
Jeśli chcesz po prostu zrobić coś N razy i nie potrzebujesz iteratora.
Odpowiedzi:
Z czubka mojej głowy, nie.
Myślę, że najlepsze, co możesz zrobić, to coś takiego:
def loop(f,n):
for i in xrange(n): f()
loop(lambda: <insert expression here>, 5)
Ale myślę, że możesz po prostu żyć z dodatkową i
zmienną.
Oto opcja użycia _
zmiennej, która w rzeczywistości jest tylko inną zmienną.
for _ in range(n):
do_something()
Zauważ, że _
przypisany jest ostatni wynik, który powrócił w interaktywnej sesji Pythona:
>>> 1+2
3
>>> _
3
Z tego powodu nie użyłbym tego w ten sposób. Nie znam żadnego idiomu wspomnianego przez Ryana. Może to zepsuć twojego tłumacza.
>>> for _ in xrange(10): pass
...
>>> _
9
>>> 1+2
3
>>> _
9
Zgodnie z gramatyką Pythona jest to dopuszczalna nazwa zmiennej:
identifier ::= (letter|"_") (letter | digit | "_")*
_
wyjaśnia, że należy go zignorować. Powiedzenie, że nie ma sensu tego robić, jest jak powiedzenie, że nie ma sensu komentować kodu - ponieważ i tak zrobiłby dokładnie to samo.
Być może szukasz
for _ in itertools.repeat(None, times): ...
jest to najszybszy sposób na iterację times
czasów w Pythonie.
To, co wszyscy sugerują używać _ nie mówi, że _ jest często używany jako skrót do jednej z funkcji gettext , więc jeśli chcesz, aby twoje oprogramowanie było dostępne w więcej niż jednym języku, najlepiej jest unikać jego używania. do innych celów.
import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print _('This is a translatable string.')
_
wydaje się okropnym pomysłem, nie miałbym nic przeciwko temu.
Oto przypadkowy pomysł, który wykorzystuje (nadużywa?) Model danych ( link 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
Zastanawiam się, czy jest coś takiego w standardowych bibliotekach?
__nonzero__
efekty uboczne to okropny pomysł.
__call__
zamiast tego. while x():
nie jest trudniejsze do napisania.
Counter
; pewnie, to nie jest zarezerwowane ani wbudowane, ale collections.Counter
jest rzeczą , a zrobienie klasy o tej samej nazwie grozi zamieszaniem opiekuna (nie to, że to już nie ryzykuje).
Możesz użyć _11 (lub dowolnej liczby lub innego nieprawidłowego identyfikatora), aby zapobiec kolizji nazw z gettext. Za każdym razem, gdy użyjesz podkreślenia + nieprawidłowego identyfikatora, otrzymujesz fałszywą nazwę, której można użyć w pętli.
Być może odpowiedź zależy od tego, jaki masz problem z używaniem iteratora? może być użyty
i = 100
while i:
print i
i-=1
lub
def loop(N, doSomething):
if not N:
return
print doSomething(N)
loop(N-1, doSomething)
loop(100, lambda a:a)
ale szczerze mówiąc, nie widzę sensu w stosowaniu takich podejść
sys.getrecursionlimit()
(domyślnie gdzieś w dolnej czwórce zakres cyfr na CPython); użycie sys.setrecursionlimit
zwiększy limit, ale w końcu osiągniesz limit stosu C, a tłumacz umrze z przepełnieniem stosu (nie tylko podniesienie ładnego RuntimeError
/ RecursionError
).
t=0
for _ in range(10):
print t
t = t+1
WYNIK:
0
1
2
3
4
5
6
7
8
9
Zamiast niepotrzebnego licznika masz teraz niepotrzebną listę. Najlepszym rozwiązaniem jest użycie zmiennej zaczynającej się od „_”, która mówi kontrolerom składni, że masz świadomość, że nie używasz zmiennej.
x = range(5)
while x:
x.pop()
print "Work!"
Ogólnie zgadzam się z powyższymi rozwiązaniami. Mianowicie z:
for
pętli (2 i więcej linii)while
licznika (3 i więcej linii)__nonzero__
implementacją (wiele innych wierszy)Jeśli ktoś jest określenie przedmiotu jak w # 3 Polecam dla wdrażania protokołu z hasła lub zastosować contextlib .
Dalej proponuję jeszcze inne rozwiązanie. Jest 3-liniowy i nie ma najwyższej elegancji, ale wykorzystuje pakiet itertools , a zatem może być interesujący.
from itertools import (chain, repeat)
times = chain(repeat(True, 2), repeat(False))
while next(times):
print 'do stuff!'
W tym przykładzie 2 oznacza liczbę powtórzeń pętli. łańcuch owija dwa powtarzające się iteratory, pierwszy jest ograniczony, ale drugi jest nieskończony. Pamiętaj, że są to prawdziwe obiekty iteratora, dlatego nie wymagają nieskończonej pamięci. Oczywiście jest to znacznie wolniejsze niż rozwiązanie nr 1 . Chyba napisany jako część funkcji może wymagać oczyszczenia do krotnie zmiennej.
chain
jest niepotrzebne, times = repeat(True, 2); while next(times, False):
robi to samo.
Mieliśmy trochę zabawy z następującymi, którymi warto się podzielić:
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()
Wyniki:
0
1
2
3
4
5
6
---------
7
Jeśli do_something
jest to prosta funkcja lub może być w nią zapakowana, proste czasy map()
mogą 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)
Jeśli chcesz przekazać argumenty do_something
, może się okazać, że przepis itertoolsrepeatfunc
brzmi dobrze:
Aby przekazać te same argumenty:
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)
Aby przekazać różne argumenty:
argses = [(1, 2), (3, 4), ...]
deque(starmap(do_something, argses), 0)
Jeśli naprawdę chcesz uniknąć umieszczenia czegoś o nazwie (zmienna iteracyjna jak w OP, niechciana lista lub niechciany generator zwracający prawdziwą pożądaną ilość czasu), możesz to zrobić, jeśli naprawdę chcesz:
for type('', (), {}).x in range(somenumber):
dosomething()
Stosowana sztuczka polega na utworzeniu anonimowej klasy, type('', (), {})
której wynikiem jest klasa o pustej nazwie, ale należy pamiętać, że nie jest ona wstawiana do lokalnej lub globalnej przestrzeni nazw (nawet jeśli podano niepustą nazwę). Następnie używasz członka tej klasy jako zmiennej iteracyjnej, która jest nieosiągalna, ponieważ klasa, do której należy, jest nieosiągalna.
#Return first n items of the iterable as a list
list(itertools.islice(iterable, n))
Zaczerpnięte z http://docs.python.org/2/library/itertools.html
Co powiesz na:
while range(some_number):
#do something
range(some_number)
jest zawsze spełniony!
some_number
jest mniejsza lub równa 0
, nie jest nieskończona, po prostu nigdy nie działa. :-) Jest to raczej nieefektywne w przypadku nieskończonej pętli (szczególnie w Py2), ponieważ tworzy nowy list
(Py2) lub range
obiekt (Py3) dla każdego testu (nie jest to stały z punktu widzenia interpretera, musi się załadować range
i some_number
każdą pętlę, wywołaj range
, a następnie przetestuj wynik).