klassen - python yield deutsch




Erstellen Sie einen Basic Python Iterator (5)

Wie würde man eine iterative Funktion (oder ein Iterator-Objekt) in Python erstellen?


Dies ist eine iterierbare Funktion ohne yield . Es nutzt die iter Funktion und eine Closure, die ihren Zustand in einem umschließenden Bereich für Python 2 in einer veränderlichen ( list ) hält.

def count(low, high):
    counter = [0]
    def tmp():
        val = low + counter[0]
        if val < high:
            counter[0] += 1
            return val
        return None
    return iter(tmp, None)

Bei Python 3 wird der Abschlussstatus im umschließenden Bereich unveränderlich gehalten und im lokalen Bereich wird nonlocal , um die Statusvariable zu aktualisieren.

def count(low, high):
    counter = 0
    def tmp():
        nonlocal counter
        val = low + counter
        if val < high:
            counter += 1
            return val
        return None
    return iter(tmp, None)  

Prüfung;

for i in count(1,10):
    print(i)
1
2
3
4
5
6
7
8
9

Diese Frage betrifft iterierbare Objekte, nicht Iteratoren. In Python sind Sequenzen auch iterierbar, sodass eine iterierbare Klasse so gestaltet werden kann, dass sie sich wie eine Sequenz verhält, dh, geben Sie __len__ Methoden __getitem__ und __len__ . Ich habe das auf Python 2 und 3 getestet.

class CustomRange:

    def __init__(self, low, high):
        self.low = low
        self.high = high

    def __getitem__(self, item):
        if item >= len(self):
            raise IndexError("CustomRange index out of range")
        return self.low + item

    def __len__(self):
        return self.high - self.low


cr = CustomRange(0, 10)
for i in cr:
    print(i)

Ich sehe einige von euch, die in __iter__ . Ich wollte nur darauf hinweisen, dass __iter__ selbst ein Generator sein kann (dadurch entfällt die Notwendigkeit für __next__ und das Anheben von StopIteration Ausnahmen).

class range:
  def __init__(self,a,b):
    self.a = a
    self.b = b
  def __iter__(self):
    i = self.a
    while i < self.b:
      yield i
      i+=1

Natürlich kann man hier auch direkt einen Generator erzeugen, aber für komplexere Klassen kann es nützlich sein.


Wenn Sie etwas kurz und einfach suchen, wird es vielleicht für Sie genug sein:

class A(object):
    def __init__(self, l):
        self.data = l

    def __iter__(self):
        return iter(self.data)

Anwendungsbeispiel:

In [3]: a = A([2,3,4])

In [4]: [i for i in a]
Out[4]: [2, 3, 4]

Iteratorobjekte in Python entsprechen dem Iteratorprotokoll, was bedeutet, dass sie zwei Methoden bereitstellen: __iter__() und next() . Der __iter__ gibt das Iterator-Objekt zurück und wird implizit am Anfang von Schleifen aufgerufen. Die next() -Methode gibt den nächsten Wert zurück und wird implizit bei jedem Schleifeninkrement aufgerufen. next() löst eine StopIteration-Ausnahme aus, wenn es keinen zurückzugebenden Wert mehr gibt, der implizit von Schleifenkonstrukten erfasst wird, um die Iteration zu stoppen.

Hier ist ein einfaches Beispiel für einen Zähler:

class Counter:
    def __init__(self, low, high):
        self.current = low
        self.high = high

    def __iter__(self):
        return self

    def next(self): # Python 3: def __next__(self)
        if self.current > self.high:
            raise StopIteration
        else:
            self.current += 1
            return self.current - 1


for c in Counter(3, 8):
    print c

Dies wird gedruckt:

3
4
5
6
7
8

Dies ist einfacher zu schreiben mit einem Generator, wie in einer vorherigen Antwort behandelt:

def counter(low, high):
    current = low
    while current <= high:
        yield current
        current += 1

for c in counter(3, 8):
    print c

Die gedruckte Ausgabe wird gleich sein. Unter der Haube unterstützt das Generator-Objekt das Iterator-Protokoll und macht so etwas wie die Klasse Counter.

David Mertz 'Artikel, Iteratoren und einfache Generatoren , ist eine ziemlich gute Einführung.







iterator