Python-Anfänger-Tutorial: für Schleifen und Iteratoren

Einführung und Anatomie einer For-Schleife

Wir beginnen also mit einigen Grundlagen, damit alle auf derselben Seite sind. Die grundlegende Anatomie einer for-Schleife sieht ungefähr so ​​​​aus:

for x in y:
    do_stuff(x,y)
  • do_stuff(x,y) ist ein Funktionsaufruf. Wenn Sie noch nicht wissen, wie Funktionen funktionieren, lohnt es sich, dies nachzuschlagen, bevor Sie hier fortfahren
  • y ist ein wiederholbar. Wir werden in Kürze auf die Details eingehen, was das bedeutet. Im Moment ist ein Iterable alles, worüber Sie iterieren können (keine Panik).
  • x ist eine Dummy-Variable und kann in verschiedenen Formen auftreten

Hier sind ein paar Beispiele für for-Schleifen, die die grundlegenden Konzepte festigen sollten:

Bereich

range ist ziemlich nützlich, wenn wir etwas eine ganzzahlige Anzahl von Malen machen wollen

for i in range(4):
    print i

Dies gibt aus:

0
1
2
3

Dieses Beispiel verwendet range in seiner einfachsten Form. Weitere Informationen darüber, wie range works geben Sie Folgendes an der Python-Eingabeaufforderung ein:

help(range)

Saiten

Einfache alte Zeichenfolgen sind auch iterierbar.

for s in "hello":
    print s

Dies gibt aus:

h
e
l
l
o

Listen

Dies sind wahrscheinlich die offensichtlichsten Iterables.

for x in [None,3,4.5,"foo",lambda : "moo",object,object()]:
    print "{0}  ({1})".format(x,type(x))

Dies gibt aus:

None  (<type 'NoneType'>)
3  (<type 'int'>)
4.5  (<type 'float'>)
foo  (<type 'str'>)
<function <lambda> at 0x7feec7fa7578>  (<type 'function'>)
<type 'object'>  (<type 'type'>)
<object object at 0x7feec7fcc090>  (<type 'object'>)

Das mag kompliziert aussehen, aber die Take-Home-Botschaft ist, dass eine Liste alles enthalten kann und eine implizite Reihenfolge hat.

Tupel

Tupel unterscheiden sich von Listen in einigen grundlegenden Punkten, die den Rahmen dieses Tutorials sprengen würden. Sie werden feststellen, dass das Iterable im folgenden Beispiel runde statt eckige Klammern verwendet und dass die Ausgabe dieselbe ist wie die Ausgabe für das obige Listenbeispiel.

for x in (None,3,4.5,"foo",lambda : "moo",object,object()):
    print "{0}  ({1})".format(x,type(x))

Dies gibt aus:

None  (<type 'NoneType'>)
3  (<type 'int'>)
4.5  (<type 'float'>)
foo  (<type 'str'>)
<function <lambda> at 0x7feec7fa7578>  (<type 'function'>)
<type 'object'>  (<type 'type'>)
<object object at 0x7feec7fcc090>  (<type 'object'>)

Wörterbücher

Ein Wörterbuch ist eine ungeordnete Liste von Schlüsselwertpaaren. Wenn Sie mit einer for-Schleife über ein Wörterbuch iterieren, wird Ihre Dummy-Variable mit den verschiedenen Schlüsseln gefüllt.

d = {
  'apples' : 'tasty',
  'bananas' : 'the best',
  'brussel sprouts' : 'evil',
  'cauliflower' : 'pretty good'
}

for sKey in d:
  print "{0} are {1}".format(sKey,d[sKey])

Dies gibt aus:

brussel sprouts are evil
apples are tasty
cauliflower are pretty good
bananas are the best

Aber vielleicht nicht ganz in dieser Reihenfolge. Ich wiederhole: Wörterbücher sind ungeordnet!

Fortgeschrittene For-Schleifen: Verwenden break und continue

Manchmal ist es notwendig, eine Schleife zu stoppen. Dies wird durch die Verwendung von erreicht break Aussage. Hier ist ein einfaches Beispiel:

for i in range(4000000000):
        print i
        if i>=2:
            break

Dies wird ausgeben:

0
1
2

Die break-Anweisung schaut auf das nächste enthaltende Schleifenende und bewirkt, dass sie beendet wird. Es funktioniert auch für While-Schleifen. Hier ist ein weiteres Beispiel, das zeigt, wie es mit verschachtelten Schleifen funktionieren würde

for ii in range(2):
    print "outer loop iteration"
    for i in range(4000000000):     
        print i
        if i>=2:
            break

Dies gibt aus:

outer loop iteration
0
1
2
outer loop iteration
0
1
2

Ein weiteres häufiges Szenario besteht darin, den Rest der aktuellen Schleifeniteration zu überspringen, aber in der Schleife zu bleiben. Dies wird mit der erreicht continue Aussage. Wie break -Anweisung, wird auch nur die nächste enthaltende Schleife betrachtet. Hier ist ein Beispiel:

iSum = 0
    iProduct =1

for i in range(5):
    print i
    if i%2==0:           
        print "even" 
        continue 
    else:
        print "odd"
    print "calculating"
    iSum = iSum + i
    iProduct = iProduct * i

print "========="
print iSum
print iProduct

Dies gibt aus:

0
even
1
odd
calculating
2
even
3
odd
calculating
4
even
=========
4
3

Für Schleifen hinter den Kulissen

Was ist überhaupt ein Iterable? Nun, die kurze Antwort ist, alles mit einem __iter__ Funktion. Das __iter__ function ist eine dieser speziellen Funktionen, auf die Python angewiesen ist. Geben Sie dieses Zeug an der Python-Eingabeaufforderung ein und sehen Sie, was passiert:

'__iter__' in dir([1,2,3])           
'__iter__' in dir((1,2,3))           
'__iter__' in dir(range(3))      
'__iter__' in dir(3)                   

So 3, eine ganze Zahl, ist nicht iterierbar. Versuche dies:

for i in 3:
    print i

Dies gibt uns den Fehler:

TypeError: 'int' object is not iterable

OK. So __iter__ ist wichtig. Was tut es? Nun, es gibt einen Iterator zurück.

Hier ist eine wirklich einfache Beispielschleife, die wir für den Rest dieser Diskussion verwenden werden:

my_list = [1,2,3]
for i in my_list:
    print i

Folgendes wird ausgegeben:

1
2
3

Das war also ziemlich einfach. Mal sehen, ob wir die gleiche Ausgabe erhalten können, ohne eine for-Schleife zu verwenden (vorausgesetzt, wir wissen vorher nicht, was in my_list steht). Hier kommen Iteratoren ins Spiel.

my_iterator = my_list.__iter__()

my_iterator ist ein listiterator Objekt. Das klingt ziemlich schick, aber lassen Sie sich nicht einschüchtern. Bald können Sie Ihre eigenen Iteratoren erstellen.

Jetzt, my_iterator hat eine Reihe von Funktionen. Derjenige, an dem wir interessiert sind, heißt next. Probieren Sie das aus:

while True:
    print my_iterator.next()  

Das druckt etwa so aus:

1
2
3
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
 StopIteration

Das ist fast das, was wir wollen. Aber jetzt my_iterator scheint kaputt zu sein: Es hat das Ende der Liste erreicht und kann nicht weiter gehen.

Hier ist eine kleine Zusammenfassung dessen, was wir bisher gelernt haben:

  • For-Schleifen durchlaufen Iterables.
  • iterables haben __iter__ Funktionen
  • __iter__ Funktionen geben Iteratoren zurück
  • Iteratoren nutzen die next -Methode, um von Element zu Element innerhalb der zugehörigen Iterable zu wechseln
  • Sobald einem Iterator die Dinge ausgehen, die er zurückgeben kann next Funktion hebt es die StopIteration Ausnahme, wenn next aufgerufen wird

Lassen Sie uns nun eine Funktion erstellen, die genau wie die for-Schleife am Anfang dieses Abschnitts funktioniert:

def my_for_loop(some_iterable):
    oIter = some_iterable.__iter__()
    while True:
        try:
            print oIter.next()
        except StopIteration:
            break

Und probieren wir es aus:

my_for_loop([1,2,3])

Dies gibt aus:

1
2
3

Genau das, was wir wollten. Spielen Sie ein wenig damit herum und sehen Sie, was passiert, wenn Sie die Iterables aus den einführenden Beispielen dieses Tutorials übergeben.

Verwenden __iter__ um Iteratoren aus Ihren Objekten zu machen

Und schließlich die coolen Sachen. Wir werden jetzt unsere eigenen Objekte iterierbar machen. Ich werde den Ansatz beschreiben, den ich normalerweise verwende. Ich benutze es, weil es einfach und prägnant ist. Ich verwende dieselbe Klasse sowohl für den Iterator als auch für das Iterable. Dies ist nützlich, wenn Sie nur einen Iterator für Ihre Klasse benötigen (was meistens der Fall ist).

class FibIterable:
    """
    this class is a generates a well known sequence of numbers 
    """
    def __init__(self,iLast=1,iSecondLast=0,iMax=50):
        self.iLast = iLast 
        self.iSecondLast = iSecondLast
        self.iMax = iMax  
    def __iter__(self):
        return self    
    def next(self):
        iNext = self.iLast + self.iSecondLast
        if iNext > self.iMax:
            raise StopIteration()
        self.iSecondLast = self.iLast
        self.iLast = iNext
        return iNext

o = FibIterable()
for i in o:
    print(i)

Das druckt:

1
2
3
5 
8
13
21
34
  • Um zusammenzufassen, was hier passiert ist, haben wir ein Objekt initialisiert, o der Klasse FibIterable.
  • Die aufgerufene for-Schleife o.__iter__ die gerade zurückgekommen isto
  • Für jede Iteration der for-Schleife wird die Schleife aufgerufen o.next() die den nächsten Wert in der Sequenz berechnet
  • Wenn der nächste Wert zu hoch war, wurde der nächste erhöht a StopIteration um aus der Schleife auszubrechen
  • andernfalls der geänderte Zustand von o gespeichert und der richtige nächste Wert zurückgegeben.

Diese Herangehensweise hat einige Vorteile, die ich bereits erwähnt habe: Sie ist prägnant und einfach. Es gibt jedoch Fälle, in denen Sie möglicherweise zwei Iteratoren für dieselben Daten benötigen. Wenn wir nach oben den Code erneut ausführen:

for i in o:
    print(i)

Es wird nichts gedruckt. Wir müssten die Klasse per Setting neu initialisieren o.iLast undo.iSecondLast auf ihre ursprünglichen Werte. Während dies eine definitive Schwäche ist, ist die Lösung trivial und als Übung überlassen.

Fazit

Gut gemacht, dass du so weit gekommen bist. Die Vor- und Nachteile von For-Schleifen und Iteratoren zu kennen, macht viele Dinge in Python viel einfacher. Jetzt sollten Sie in der Lage sein, dass Sie das wirklich bekommen for Schleife und ihre internen Mechanismen. Sie können for-Schleifen zum Iterieren über viele Arten von in Python eingebauten Iterables schreiben, und wenn das nicht ausreicht, können Sie sogar Ihre eigenen Iterablen erstellen.

Wenn Ihr Code sehr durchgeknallt ist und mit vielen Sammlungen zu tun hat, sind diese Fähigkeiten unverzichtbar, und ich würde vorschlagen, Ihre Ausbildung fortzusetzen, indem Sie sich mit Python-Generatoren, Listenverständnis und Sortiermechanismen vertraut machen. Auch die itertools Modul dürfte interessant sein. Wenn Ihr Code andererseits dazu neigt, Baum- oder Diagrammstrukturen und Algorithmen zu beinhalten, würde ich vorschlagen, sich mit Rekursion zu befassen. Eine elegante rekursive Funktion kann viele Zeilen verschachtelter Schleifen ersetzen.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *