__iter_, wer erklärt es mir?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Sinnentlehrt
User
Beiträge: 67
Registriert: Mittwoch 30. Januar 2013, 22:32

Hallo Leute,

versuche gerade ein Programmbeispiel zu verstehen.

Code: Alles auswählen

class Fibonacci(object): 
    def __init__(self, max_n): 
        self.MaxN = max_n 
        self.N = 0 
        self.A = 0 
        self.B = 0 
 
    def __iter__(self): 
        self.N = 0 
        self.A = 0 
        self.B = 1 
        return self 
 
    def next(self): 
        if self.N < self.MaxN: 
            self.N += 1 
            self.A, self.B = self.B, self.A + self.B 
            return self.A 
        else: 
            raise StopIteration
Wird dann so abgefragt:

Code: Alles auswählen

>>> for f in Fibonacci(14): 
        print f, 
1 1 2 3 5 8 13 21 34 55 89 144 233 377 
Das Code hat eine ausführliche Erklärung in diesem Buch:
http://openbook.galileocomputing.de/pyt ... 8c937ad98d

Ich kann zwar die Logik für die Fibonacci Zahlen nachvollziehen aber mir wird dabei die Rolle von __iter__ nicht ganz klar.

Die Erklärung im Buch deute ich so das eine for Schleife einen iter-Container einfacher als sonst durchlaufen kann. Wobei ich dieses "als sonst" nicht ganz begreife.

Der Konstruktor von class Fibonacci definiert 4 Variablen und A, B und N sind dann wohl frei in ihrer Definition weil __iter__ automatisch feststellt um welche Art von Variablen es sich handelt. Dadurch können diese ohne weitere Bestimmung von 'next' weiterverarbeitet werden.

Habe ich das so einigermaßen verstanden? Aber gibt es vielleicht noch andere Beispiele dir mir den Sinn des ganzen näher bringen können.

Grüss,
Du weißt das du vergessen hast einzukaufen, wenn du dich morgens mit Geschirrspülmittel duscht.
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Vergess das Beispiel GAAAANNNZ schnell wieder, denn so programmiert man kein python. Sowas packt man in eine Funktion und nicht in eine Klasse. Und such dir eine besseres Tutorial, das OpenBook ist in manchen Bereichen einfach nur schlecht.
BlackJack

@Sinnentlehrt: Die ``for``-Schleife ruft intern `iter()` mit dem Objekt hinter ``in`` auf. Die Funktion ruft ihrerseits die `__iter__()`-Methode auf dem Objekt auf. Und auf dem Objekt was dabei zurückgegeben wird, ruft die Laufzeitumgebung für jeden Schleifendurchlauf die `next()`-Methode auf, solange bis die eine `StopIteration` auslöst. Also ``for`` macht intern ungefähr das hier:

Code: Alles auswählen

   for item in iterable:
        do_something(item)

# Entspricht in etwa:

    iterator = iter(iterable)
    try:
        while True:
            item = iterator.next()
            do_something(item)
    except StopIteration:
        pass
Und das Wissen musst Du jetzt einfach nur noch mit dieser furchtbaren Klasse in Verbindung bringen.

Mal davon abgesehen, dass die ziemlich umständlich ist, ist sie selbst der Iterator und initialisiert sich in `__iter__()` neu. Das ist ziemlich ungewöhnlich, denn das macht soweit ich weiss kein Iterator aus der Standardbibliothek und auch sonst ist mir das noch nicht untergekommen. Der „Vertrag” mit `__iter__()` auf Iteratoren ist nämlich dass sie sich selbst einfach unverändert zurück geben. Das bedeutet, dass man Funktionen schreiben kann, die sowohl iterierbare Objekte im allgemeinen als auch Iteratoren die möglicherweise schon „angebrochen” sind, entgegen nehmen. Was mit diesen `Fibonacci` nicht möglich ist. Ist würde das als Fehler einstufen.

Edit: Man ist auch etwas flexibler wenn man das Generieren der Zahlen und das Zählen trennt. Also einen Iterator erzeugt, der endlos viele Fibonacci-Zahlen ausspuckt und davon dann nur beispielsweise die ersten 14 ausgibt:

Code: Alles auswählen

from itertools import islice


def iter_fibonacci():
    a, b = 0, 1
    while True:
        a, b = b, a + b
        yield a


def main():
    for i in islice(iter_fibonacci(), 14):
        print i,


if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo Sinnentlehrt,

die Klasse ist quatsch. Besser müßte sie so heißen:

Code: Alles auswählen

class FibonacciIterator(object): 
    def __init__(self, max_n): 
        self.max_n = max_n 
        self.n = 0 
        self.a = 0 
        self.b = 1 

    def __iter__(self): 
        return self 

    def next(self): 
        if self.n >= self.max_n: 
            raise StopIteration
        self.n += 1 
        self.a, self.b = self.b, self.a + self.b 
        return self.a

class Fibonacci(object): 
    def __init__(self, max_n): 
        self.max_n = max_n 

    def __iter__(self): 
        return FibonacciIterator(self.max_n)
dadurch wird der interne Zustand durch den Aufruf von __iter__ nicht zerstört.
In den meisten Fällen schreibt man aber keine eigene Klasse sondern einen Generator mit yield:

Code: Alles auswählen

def fibonacci(max_n):
    a, b = 0, 1
    for _n in xrange(max_n): 
        a, b = b, a+b
        yield a
Sinnentlehrt
User
Beiträge: 67
Registriert: Mittwoch 30. Januar 2013, 22:32

@anogayales, leider gibt es wohl nicht DAS python Buch, aber ich glaube ich werde mich wohl bald dem "Einstieg in Python:" http://www.amazon.de/Einstieg-Python-Pr ... 496&sr=8-2 anvertrauen

@BlackJack, nein, deine Ausführungen waren nicht gerade erhellend für mich, was ich aber auf keinen Fall dir ankreiden möchte. Aber dieses Buch scheint ja dann doch mehr als eine Stelle zu haben die man nicht empfehlen kann. Immerhin kann ich mit 'yield' schon eher etwas anfangen.

@Sirius3, das der interne Zustand von __iter__ nicht zerstört wird wollte mir glaube ich schon BlackJack näherbringen, leider scheiterte er auch damit. :cry:
Aber der xrange Generator und yield sind mir schon in Dive into Python über den Weg gelaufen, und darum belasse ich das auch dabei. Das habe ich nämlich umrissen, aber __iter__ wird erstmal nicht mehr mein Thema sein.

Danke für eure Hilfe, aber jetzt werde ich wohl einfach direkt das Buch wechseln.

Grüsse,
Du weißt das du vergessen hast einzukaufen, wenn du dich morgens mit Geschirrspülmittel duscht.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Sinnentlehrt hat geschrieben:@anogayales, leider gibt es wohl nicht DAS python Buch, aber ich glaube ich werde mich wohl bald dem "Einstieg in Python:" http://www.amazon.de/Einstieg-Python-Pr ... 496&sr=8-2 anvertrauen
Auch wieder von dem Verlag der Wahllos Bücher publiziert ohne die Qualifikation der Autoren zu hinterfragen? Naja :roll:
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten