Mehr pythonische Möglichkeit, einen Prozess X-mal auszuführen

88

Was ist pythonischer?

While-Schleife:

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

For-Schleife:

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

Bearbeiten: nicht duplizieren, da dies Antworten enthält, um zu bestimmen, welche klarer sind, als wie ein Bereich ohne 'i' ausgeführt werden soll - obwohl dies am elegantesten war

Lionel
quelle
8
Upvoting, um die Abwärtsstimmen zu kompensieren: Wenn Lionel diese Frage stellt, haben andere möglicherweise dieselbe Frage, und die folgenden Antworten sind hilfreich.
Eric O Lebigot
2
Der Begriff "Pythonic" wird überstrapaziert. Es ist ein Synonym für "lesbar" und "leicht verständlich". Zumindest in Python.
Darioo
Mögliches Duplikat von Ist es möglich, eine Python for Range-Schleife ohne Iteratorvariable zu implementieren?
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

Antworten:

108

Persönlich:

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

wenn du nicht brauchst i. Wenn Sie Python <3 verwenden und die Schleife häufig wiederholen möchten, verwenden Sie diese Option, xrangeda Sie nicht die gesamte Liste im Voraus generieren müssen.

Felix Kling
quelle
15
Achten Sie jedoch darauf, dass _ der Gettext-Übersetzungsfunktion zugeordnet wird.
Gintautas Miliauskas
10
+1 für die _Variable. Das hätte ich vorgeschlagen.
Eric O Lebigot
6
_ ist wie jede andere Variable. Nur in der REPL hat es eine besondere Bedeutung. Das OP kann genauso gut bleiben i.
vezult
2
@vezult Ich mag das, da es klar macht, dass die Variable in der Anweisung nicht verwendet wird. Gibt es vielleicht einen Grund, der dies überschattet, um bei dem zu bleiben i?
Ryanjdillon
6
Ich bin fest davon überzeugt, Ponys hinzuzufügen, besonders wenn es angemessen klingt ... für Pony in Reichweite (50): print ("wiehern") #python 3
Paul
3

Die for-Schleife ist definitiv pythonischer, da sie die übergeordnete integrierte Funktionalität von Python verwendet, um klarer und präziser zu vermitteln, was Sie tun. Der Overhead von range vs xrange und das Zuweisen einer nicht verwendeten iVariablen ergibt sich aus dem Fehlen einer Anweisung wie der von Verilog repeat. Der Hauptgrund, sich an die for range-Lösung zu halten, ist, dass andere Wege komplexer sind. Zum Beispiel:

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"

Die Verwendung von Wiederholung anstelle von Bereich ist hier weniger klar, da es sich nicht um eine so bekannte Funktion handelt, und komplexer, weil Sie sie importieren müssen. Die wichtigsten Styleguides, wenn Sie eine Referenz benötigen, sind PEP 20 - Das Zen von Python und PEP 8 - Styleguide für Python-Code .

Wir stellen außerdem fest, dass die for range-Version ein explizites Beispiel ist, das sowohl in der Sprachreferenz als auch im Lernprogramm verwendet wird , obwohl in diesem Fall der Wert verwendet wird. Dies bedeutet jedoch, dass die Form vertrauter ist als die while-Erweiterung einer for-Schleife im C-Stil.

Yann Vernier
quelle
Wäre es nicht besser, das wiederholte Ding direkt zu verwenden, dh: for s in repeat('This is run 10 times', 10): print s??
F1Rumors
Bestimmt! Der Ausdruck im Beispielcode war jedoch nur ein Beispiel für einen wiederholten Codeabschnitt, für den es möglicherweise kein zentrales Objekt gibt.
Yann Vernier
Python-Kernentwickler sagt, dies sei schneller als die Verwendung von range() twitter.com/raymondh/status/1144527183341375488
Chris_Rands
Es ist in der Tat schneller, da es nicht intfür jede Iteration nachschlagen oder ein anderes Objekt erstellen muss . Die Programmierzeit kann jedoch wertvoller sein als die Ausführungszeit.
Yann Vernier
2

Wenn Sie nach den Nebenwirkungen suchen, die innerhalb der Schleife auftreten, würde ich mich persönlich für den range()Ansatz entscheiden.

Wenn Sie sich für das Ergebnis der Funktionen interessieren, die Sie innerhalb der Schleife aufrufen, würde ich mich für ein Listenverständnis oder einen mapAnsatz entscheiden. Etwas wie das:

def f(n):
    return n * n

results = [f(i) for i in range(50)]
# or using map:
results = map(f, range(50))
knutin
quelle
Ergebnisse = (f für i im Bereich (50))
Luka Rahne
1
Ergebnisse = itertools.imap (f, Bereich (50))
Luka Rahne
@ralu, nur wenn Sie keinen wiederholten oder zufälligen Zugriff auf die Ergebnisse benötigen.
Aaronasterling
2
Ergebnis = Tupel (Ergebnisse) und ist viel schneller als Liste, da das Schneiden auf Tupel O (1) ist
Luka Rahne
-3

Wie wäre es mit?

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

oder auf hässlichere Weise:

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

oder wenn Sie das letzte Mal durch fangen wollen:

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

wo:

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__()
DangerMouse
quelle
-5

Es gibt keine wirklich pythonische Art, etwas zu wiederholen. Es ist jedoch ein besserer Weg:

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

Wenn Sie den Index übergeben müssen, dann:

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

Beachten Sie, dass die Ergebnisse als Sammlung zurückgegeben werden. Wenn Sie also die Ergebnisse sammeln müssen, kann dies hilfreich sein.

Abi M. Sangarab
quelle
Dies ist nicht nur nicht wirklich besser (Funktionsaufruf-Overhead, weniger bekannte Lambda-Ausdrücke, Sammeln nicht verwendeter Ergebnisse in einer Liste), 10 ist auch nicht iterierbar.
Yann Vernier
Ja, xrange (10) nicht 10. Ich sagte, es ist besser, weil Sie keine Funktion schreiben oder eine Schleife erstellen müssen. Wie gesagt, es gibt jedoch keinen wirklichen pythonischen Weg. Ich habe den Code geändert. Danke.
Abi M. Sangarab