Im Allgemeinen ist ein sehr guter Ansatz, __iter__
einen Generator von yield
Werte zu machen. Dies könnte weniger intuitiv sein, aber es ist geradlinig; Sie liefern nur die Ergebnisse zurück Sie wollen und __next__
wird dann automatisch für Sie bereitgestellt:
class Item:
def __iter__(self):
for item in range(0, 30, 10):
yield item
Dies ist nur die Kraft der yield
verwendet den gewünschten Effekt zu erzielen, wenn Python
Anrufe __iter__
auf Ihrem Objekt, erwartet er eine iterator
zurück (dh ein Objekt, das __next__
Anrufe unterstützt), wird ein Generator nur, dass jedes Elements der Herstellung wie in Ihrer Generatorfunktion definiert (dh __iter__
in diesem Fall), wenn __next__
genannt wird:
>>> i = iter(Item())
>>> print(i) # generator, supports __next__
<generator object __iter__ at 0x7f6aeaf9e6d0>
>>> next(i)
0
>>> next(i)
10
>>> next(i)
20
Jetzt erhalten Sie den gleichen Effekt wie __getitem__
. Der Unterschied besteht darin, dass kein index
in geben wird, müssen Sie manuell durchlaufen sie, um das Ergebnis zu erhalten:
>>> for i in Item():
... print(i)
0
10
20
Davon abgesehen, gibt es zwei Alternativen für die Erstellung eines Objekts, das Iteration unterstützt.
Einmal Looping: Stellen Sie Artikel ein Iterator
durch die Definition __next__
Item
ein Iterator Stellen und self
von __iter__
in diesem Fall zurückkehrt, da Sie yield
die __iter__
Methode gibt self
und __next__
die nicht verwenden Griffe Logik der Rückkehr Werte:
class Item:
def __init__(self):
self.val = 0
def __iter__(self):
return self
def __next__(self):
if self.val > 2: raise StopIteration
res = range(0, 30, 10)[self.val]
self.val += 1
return res
Dies nutzt auch einen Hilfs val
die resu zu erhalten lt aus dem Bereich und prüfen, ob wir noch laufen werden sollen (wenn nicht, wir erhöhen StopIteration
):
>>> for i in Item():
... print(i)
0
10
20
Das Problem bei diesem Ansatz ist, dass es eine einmalige Fahrt nach einmaligem Durchlaufen, die self.val
Punkte 3
und Iteration kann nicht erneut durchgeführt werden. (mit yield
löst dieses Problem). (Ja, Sie könnten gehen und val
auf 0 setzen, aber das ist nur hinterhältig.)
Viele Male Schleife: Erstellen Sie benutzerdefinierte Iterator-Objekt.
Der zweite Ansatz ist speziell für Ihre Item
Klassenobjekt eine benutzerdefinierte Iterator zu verwenden und sie von Item.__iter__
statt self
zurück:
class Item:
def __iter__(self):
return IterItem()
class IterItem:
def __init__(self):
self.val = 0
def __iter__(self):
return self
def __next__(self):
if self.val > 2: raise StopIteration
res = range(0, 30, 10)[self.val]
self.val += 1
return res
wird nun geliefert jedes Mal, wenn Sie eine neue benutzerdefinierte Iterator durchlaufen und Sie können unterstützt mehrere Iterationen über Item
Objekte.
auf einer realen Liste Versuchen. Die Funktion 'mylist .__ iter__' gibt einen Generator zurück. Sie können einige Schritte durch diesen Generator durchführen, indem Sie 'my_generator.next()' einige Male aufrufen. Ich würde es jedoch nicht als gleichwertig bezeichnen, da der Zugriff auf Listenelemente eine konstante Zeit ist, während die Iteration bis zu einem bestimmten Zeitpunkt eine lineare Zeit ist. –
Was ist mit 'def __iter __ (self): return (x für x im Bereich (0,30,10))'? –
@machineyearning Ich muss auch einen Index übergeben. (self, pos) – SeasonalShot