Est-il possible de suivre sans le i
?
for i in range(some_number):
# do something
Si vous voulez juste faire quelque chose N fois et n'avez pas besoin de l'itérateur.
Est-il possible de suivre sans le i
?
for i in range(some_number):
# do something
Si vous voulez juste faire quelque chose N fois et n'avez pas besoin de l'itérateur.
Réponses:
Du haut de ma tête, non.
Je pense que le mieux que vous puissiez faire est quelque chose comme ceci:
def loop(f,n):
for i in xrange(n): f()
loop(lambda: <insert expression here>, 5)
Mais je pense que vous pouvez simplement vivre avec la i
variable supplémentaire .
Voici la possibilité d'utiliser la _
variable, qui en réalité, n'est qu'une autre variable.
for _ in range(n):
do_something()
Notez que _
le dernier résultat renvoyé dans une session Python interactive est attribué:
>>> 1+2
3
>>> _
3
Pour cette raison, je ne l'utiliserais pas de cette manière. Je ne connais aucun idiome mentionné par Ryan. Cela peut gâcher votre interprète.
>>> for _ in xrange(10): pass
...
>>> _
9
>>> 1+2
3
>>> _
9
Et selon la grammaire Python , c'est un nom de variable acceptable:
identifier ::= (letter|"_") (letter | digit | "_")*
_
indique clairement qu'il doit être ignoré. Dire que cela ne sert à rien, c'est comme dire qu'il est inutile de commenter votre code - parce que cela ferait exactement la même chose de toute façon.
Vous cherchez peut-être
for _ in itertools.repeat(None, times): ...
c'est LE moyen le plus rapide d'itérer les times
temps en Python.
Ce que tout le monde vous suggère d'utiliser _ ne dit pas, c'est que _ est fréquemment utilisé comme raccourci vers l'une des fonctions de gettext , donc si vous voulez que votre logiciel soit disponible dans plus d'une langue, il vaut mieux éviter de l'utiliser à d'autres fins.
import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print _('This is a translatable string.')
_
semble être une idée terrible, cela ne me dérangerait pas d'être en conflit avec elle.
Voici une idée aléatoire qui utilise (abuse?) Le modèle de données ( lien 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
Je me demande s'il y a quelque chose comme ça dans les bibliothèques standard?
__nonzero__
des effets secondaires est une idée horrible.
__call__
place. while x():
n'est pas si difficile à écrire.
Counter
; bien sûr, ce n'est pas réservé ou dans la portée intégrée, mais collections.Counter
c'est une chose , et créer une classe du même nom risque de confondre le responsable (non pas que cela ne risque pas déjà).
Vous pouvez utiliser _11 (ou n'importe quel nombre ou un autre identifiant non valide) pour empêcher la colision de nom avec gettext. Chaque fois que vous utilisez un trait de soulignement + un identificateur non valide, vous obtenez un nom factice qui peut être utilisé dans la boucle for.
Peut-être que la réponse dépendra du problème que vous rencontrez avec l'utilisation de l'itérateur? peut être utilisé
i = 100
while i:
print i
i-=1
ou
def loop(N, doSomething):
if not N:
return
print doSomething(N)
loop(N-1, doSomething)
loop(100, lambda a:a)
mais franchement, je ne vois aucun intérêt à utiliser de telles approches
sys.getrecursionlimit()
(qui par défaut à quelque part dans les quatre plage de chiffres sur CPython); utiliser sys.setrecursionlimit
augmenterait la limite, mais finalement vous atteindriez la limite de pile C et l'interpréteur mourrait avec un débordement de pile (pas seulement en augmentant un gentil RuntimeError
/ RecursionError
).
t=0
for _ in range(10):
print t
t = t+1
PRODUCTION:
0
1
2
3
4
5
6
7
8
9
Au lieu d'un compteur inutile, vous avez maintenant une liste inutile. La meilleure solution consiste à utiliser une variable commençant par «_», qui indique aux vérificateurs de syntaxe que vous savez que vous n'utilisez pas la variable.
x = range(5)
while x:
x.pop()
print "Work!"
Je suis généralement d'accord avec les solutions données ci-dessus. A savoir avec:
for
-loop (2 lignes et plus)while
compteur normal (3 lignes et plus)__nonzero__
implémentation (beaucoup plus de lignes)Si l'on doit définir un objet comme au n ° 3, je recommanderais d'implémenter le protocole avec un mot - clé ou d'appliquer contextlib .
De plus, je propose encore une autre solution. Il s'agit d'un 3 lignes et n'est pas d'une élégance suprême, mais il utilise le package itertools et pourrait donc être d'un intérêt.
from itertools import (chain, repeat)
times = chain(repeat(True, 2), repeat(False))
while next(times):
print 'do stuff!'
Dans cet exemple, 2 est le nombre d'itérations de la boucle. chain encapsule deux itérateurs répétés , le premier étant limité mais le second est infini. Rappelez-vous que ce sont de véritables objets itérateurs, donc ils ne nécessitent pas de mémoire infinie. Évidemment, c'est beaucoup plus lent que la solution n ° 1 . À moins d'être écrit dans le cadre d'une fonction, il peut nécessiter un nettoyage de la variable times .
chain
est inutile, times = repeat(True, 2); while next(times, False):
fait la même chose.
Nous nous sommes amusés avec ce qui suit, intéressant à partager donc:
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()
Résultats:
0
1
2
3
4
5
6
---------
7
Si do_something
est une fonction simple ou peut être enveloppée dans une seule, une simple map()
boîte peut do_something
range(some_number)
fois:
# 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)
Si vous souhaitez passer des arguments à do_something
, vous pouvez également trouver que la recette itertools serepeatfunc
lit bien:
Pour passer les mêmes arguments:
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)
Pour passer différents arguments:
argses = [(1, 2), (3, 4), ...]
deque(starmap(do_something, argses), 0)
Si vous voulez vraiment éviter de mettre quelque chose avec un nom (soit une variable d'itération comme dans l'OP, soit une liste indésirable ou un générateur indésirable renvoyant vrai le temps voulu), vous pouvez le faire si vous le souhaitez vraiment:
for type('', (), {}).x in range(somenumber):
dosomething()
L'astuce utilisée est de créer une classe anonyme type('', (), {})
qui aboutit à une classe avec un nom vide, mais NB qu'elle n'est pas insérée dans l'espace de noms local ou global (même si un nom non vide a été fourni). Ensuite, vous utilisez un membre de cette classe comme variable d'itération qui est inaccessible car la classe dont il est membre est inaccessible.
#Return first n items of the iterable as a list
list(itertools.islice(iterable, n))
Qu'en est-il de:
while range(some_number):
#do something
range(some_number)
est toujours vraie!
some_number
est inférieur ou égal à 0
, ce n'est pas infini, il ne s'exécute jamais. :-) Et c'est plutôt inefficace pour une boucle infinie (surtout sur Py2), car cela crée un list
(Py2) ou un range
objet (Py3) frais pour chaque test (ce n'est pas une constante du point de vue de l'interpréteur, il faut charger range
et some_number
chaque boucle, appelez range
, puis testez le résultat).