web-dev-qa-db-fra.com

façon pythonique de faire quelque chose N fois sans variable d’index?

Chaque jour, j'aime python de plus en plus.

Aujourd'hui, j'écrivais du code comme:

for i in xrange(N):
    do_something()

Je devais faire quelque chose N fois. Mais chaque fois ne dépendait pas de la valeur de i (variable d'index). J'ai réalisé que je créais une variable que je n'avais jamais utilisée (i) et je me suis dit: "Il existe sûrement un moyen plus pythonique de le faire sans avoir besoin de cette variable d'index inutile."

Alors ... la question est: savez-vous comment effectuer cette tâche simple de manière plus belle (Pythonic)?

138
Manuel Aráoz

Une approche légèrement plus rapide que la boucle sur xrange(N) est:

import itertools

for _ in itertools.repeat(None, N):
    do_something()
100
Alex Martelli

Utilisez la variable _, comme je l'ai appris lorsque j'ai posé cette question question , par exemple:

# A long way to do integer exponentiation
num = 2
power = 3
product = 1
for _ in xrange(power):
    product *= num
print product
51
GreenMatt

Je viens d'utiliser for _ in range(n), c'est droit au but. Il va générer la liste complète des nombres énormes dans Python 2, mais si vous utilisez Python 3, ce n'est pas un problème.

Le _ est la même chose que x. Cependant, c’est un idiome python utilisé pour indiquer un identifiant que vous n’avez pas l’intention d’utiliser. Dans python ces identifiants ne prennent pas de mémoire ou allouent de l’espace comme les variables dans d'autres langues, c'est facile à oublier, ce sont simplement des noms qui pointent vers des objets, dans ce cas un entier à chaque itération.

9
Khorkrak

puisque la fonction est un citoyen de première classe, vous pouvez écrire un petit wrapper (d'après Alex)

def repeat(f, N):
    for _ in itertools.repeat(None, N): f()

alors vous pouvez passer la fonction comme argument.

9
Anycorn

J'ai trouvé les différentes réponses très élégantes (en particulier celles d'Alex Martelli), mais je voulais quantifier directement les performances, j'ai donc concocté le script suivant:

from itertools import repeat
N = 10000000

def payload(a):
    pass

def standard(N):
    for x in range(N):
        payload(None)

def underscore(N):
    for _ in range(N):
        payload(None)

def loopiter(N):
    for _ in repeat(None, N):
        payload(None)

def loopiter2(N):
    for _ in map(payload, repeat(None, N)):
        pass

if __== '__main__':
    import timeit
    print("standard: ",timeit.timeit("standard({})".format(N),
        setup="from __main__ import standard", number=1))
    print("underscore: ",timeit.timeit("underscore({})".format(N),
        setup="from __main__ import underscore", number=1))
    print("loopiter: ",timeit.timeit("loopiter({})".format(N),
        setup="from __main__ import loopiter", number=1))
    print("loopiter2: ",timeit.timeit("loopiter2({})".format(N),
        setup="from __main__ import loopiter2", number=1))

J'ai également proposé une solution alternative qui s'appuie sur celle de Martelli et utilise map() pour appeler la fonction de charge utile. OK, j'ai un peu triché en prenant la liberté de faire accepter par la charge utile un paramètre qui est jeté: je ne sais pas s'il y a moyen de contourner cela. Néanmoins, voici les résultats:

standard:  0.8398549720004667
underscore:  0.8413165839992871
loopiter:  0.7110594899968419
loopiter2:  0.5891903560004721

l'utilisation de la carte génère donc une amélioration d'environ 30% par rapport à la norme pour la boucle et de 19% supplémentaire par rapport à celle de Martelli.

5
japs

Supposons que vous ayez défini do_something en tant que fonction et que vous souhaitiez l'exécuter N fois. Peut-être que vous pouvez essayer ce qui suit:

todos = [do_something] * N  
for doit in todos:  
    doit()
4
Cox Chen

Qu'en est-il d'une simple boucle while?

while times > 0:
    do_something()
    times -= 1

Vous avez déjà la variable; pourquoi ne pas l'utiliser?

0
Carlos Ramirez