Une manière plus pythonique d'exécuter un processus X fois

90

Lequel est le plus pythonique?

En boucle:

count = 0
while count < 50:
    print "Some thing"
    count = count + 1

Pour la boucle:

for i in range(50):
    print "Some thing"

Edit: ne pas dupliquer car cela a des réponses pour déterminer ce qui est le plus clair, vs comment exécuter une plage sans `` i '' - même si cela a fini par être le plus élégant

Lionel
la source
8
Le vote pour compenser les votes négatifs: si Lionel pose cette question, d'autres pourraient avoir la même question, et les réponses ci-dessous seront utiles.
Eric O Lebigot
2
Le terme «pythonique» est surutilisé. C'est un synonyme de «lisible» et de «facilement compréhensible». En Python, au moins.
darioo
Possibilité de duplication de Est-il possible d'implémenter une boucle Python for range sans variable d'itérateur?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:

111

Personnellement:

for _ in range(50):
    print "Some thing"

si vous n'en avez pas besoin i. Si vous utilisez Python <3 et que vous souhaitez répéter la boucle plusieurs fois, utilisez xrangecar il n'est pas nécessaire de générer la liste complète au préalable.

Félix Kling
la source
15
Attention cependant à _ être mappé à la fonction de traduction gettext.
Gintautas Miliauskas
Merci pour cette réponse; c'était la raison principale pour laquelle je n'utilisais pas la boucle for parce que j'avais une variable inutilisée dans "i".
Lionel
6
_ est comme n'importe quelle autre variable. Ce n'est que dans la REPL qu'il a une signification particulière. L'OP peut tout aussi bien s'en tenir i.
vezult
2
@vezult J'aime cela car cela montre clairement que la variable n'est pas utilisée dans l'instruction. Y a-t-il peut-être une raison qui éclipse cela pour s'en tenir à la i?
ryanjdillon
6
Je crois fermement à l'ajout de poneys, surtout quand cela semble approprié ... pour poney à portée (50): print ("hennir") #python 3
Paul
3

La boucle for est définitivement plus pythonique, car elle utilise la fonctionnalité intégrée de niveau supérieur de Python pour transmettre ce que vous faites à la fois plus clairement et plus précisément. La surcharge de range vs xrange, et l'attribution d'une ivariable inutilisée , proviennent de l'absence d'une instruction comme celle de Verilog repeat. La principale raison de s'en tenir à la solution pour la plage est que les autres méthodes sont plus complexes. Par exemple:

from itertools import repeat

for unused in repeat(None, 10):
    del unused   # redundant and inefficient, the name is clear enough
    print "This is run 10 times"

L'utilisation de la répétition au lieu de la plage est ici moins claire car ce n'est pas une fonction aussi connue, et plus complexe car vous devez l'importer. Les principaux guides de style si vous avez besoin d'une référence sont PEP 20 - Le Zen de Python et PEP 8 - Guide de style pour le code Python .

Nous notons également que la version for range est un exemple explicite utilisé à la fois dans la référence de langage et dans le didacticiel , bien que dans ce cas, la valeur soit utilisée. Cela signifie que la forme est forcément plus familière que l'expansion while d'une boucle for de style C.

Yann Vernier
la source
Ne serait-il pas préférable d'utiliser directement la chose répétée, c'est-à-dire: for s in repeat('This is run 10 times', 10): print s??
F1Rumors
Certainement! Mais l'impression dans l'exemple de code n'était qu'un exemple d'une section répétée de code, pour laquelle il peut ne pas y avoir d'objet central.
Yann Vernier
Le développeur principal de Python dit que c'est plus rapide que d'utiliser range() twitter.com/raymondh/status/1144527183341375488
Chris_Rands
C'est en effet plus rapide, car il n'a pas besoin de rechercher ou de créer un intobjet différent pour chaque itération. Cependant, le temps du programmeur peut être plus précieux que le temps d'exécution.
Yann Vernier
2

Si vous recherchez les effets secondaires qui se produisent dans la boucle, je choisirais personnellement l' range()approche.

Si vous vous souciez du résultat des fonctions que vous appelez dans la boucle, j'opterais pour une compréhension ou une mapapproche de liste . Quelque chose comme ça:

def f(n):
    return n * n

results = [f(i) for i in range(50)]
# or using map:
results = map(f, range(50))
knutin
la source
résultats = (f pour i dans l'intervalle (50))
Luka Rahne
1
results = itertools.imap (f, range (50))
Luka Rahne
@ralu, uniquement si vous n'avez pas besoin d'un accès répété ou aléatoire aux résultats.
aaronasterling
2
result = tuple (résultats) et est beaucoup plus rapide que la liste, car le découpage sur tuple est O (1)
Luka Rahne
-3

Que diriez-vous?

while BoolIter(N, default=True, falseIndex=N-1):
    print 'some thing'

ou d'une manière plus moche:

for _ in BoolIter(N):
    print 'doing somthing'

ou si vous voulez attraper la dernière fois à travers:

for lastIteration in BoolIter(N, default=False, trueIndex=N-1):
    if not lastIteration:
        print 'still going'
    else:
        print 'last time'

où:

class BoolIter(object):

    def __init__(self, n, default=False, falseIndex=None, trueIndex=None, falseIndexes=[], trueIndexes=[], emitObject=False):
        self.n = n
        self.i = None
        self._default = default
        self._falseIndexes=set(falseIndexes)
        self._trueIndexes=set(trueIndexes)
        if falseIndex is not None:
            self._falseIndexes.add(falseIndex)
        if trueIndex is not None:
            self._trueIndexes.add(trueIndex)
        self._emitObject = emitObject


    def __iter__(self):
        return self

    def next(self):
        if self.i is None:
            self.i = 0
        else:
            self.i += 1
        if self.i == self.n:
            raise StopIteration
        if self._emitObject:
            return self
        else:
            return self.__nonzero__()

    def __nonzero__(self):
        i = self.i
        if i in self._trueIndexes:
            return True
        if i in self._falseIndexes:
            return False
        return self._default

    def __bool__(self):
        return self.__nonzero__()
Danger Souris
la source
-5

Il n'y a pas de manière vraiment pythonique de répéter quelque chose. Cependant, c'est un meilleur moyen:

map(lambda index:do_something(), xrange(10))

Si vous devez passer l'index, alors:

map(lambda index:do_something(index), xrange(10))

Considérez qu'il renvoie les résultats sous forme de collection. Donc, si vous avez besoin de collecter les résultats, cela peut vous aider.

Abi M.Sangarab
la source
Non seulement ce n'est pas vraiment mieux (surcharge d'appel de fonction, expressions lambda moins connues, collecte des résultats inutilisés dans une liste), 10 n'est pas une itération.
Yann Vernier
Oui, xrange (10) pas 10. J'ai dit que c'était mieux parce que vous n'avez pas besoin d'écrire une fonction ou de faire une boucle. Cependant, comme je l'ai dit, il n'y a pas de véritable voie pythonique. J'ai changé le code, merci.
Abi M.Sangarab