Ich habe eine Klasse mit einem __iter__
und einem __len__
Methoden. Letzterer verwendet Ersteres, um alle Elemente zu zählen.Wie list() verbrauchen __iter__ ohne __len__ aufzurufen?
Es funktioniert wie folgt aus:
class A:
def __iter__(self):
print("iter")
for _ in range(5):
yield "something"
def __len__(self):
print("len")
n = 0
for _ in self:
n += 1
return n
Nun, wenn wir zum Beispiel nehmen die Länge einer Instanz druckt len
und iter
, wie erwartet:
>>> len(A())
len
iter
5
Aber wenn wir list()
nennen es nennt beide __iter__
und __len__
:
>>> list(A())
len
iter
iter
['something', 'something', 'something', 'something', 'something']
Es funktioniert wie erwartet, wenn wir einen Generator Ausdruck machen :
>>> list(x for x in A())
iter
['something', 'something', 'something', 'something', 'something']
ich würde davon ausgehen list(A())
und list(x for x in A())
funktionieren gleich, aber sie nicht.
Beachten Sie, dass es zuerst erscheint __iter__
zu nennen, dann __len__
, dann Schleife über den Iterator:
class B:
def __iter__(self):
print("iter")
def gen():
print("gen")
yield "something"
return gen()
def __len__(self):
print("len")
return 1
print(list(B()))
Ausgang:
iter
len
gen
['something']
Wie kann ich list()
nicht __len__
anrufen damit der Iterator meiner Instanz nicht zweimal verbraucht wird? Ich könnte z.B. a length
oder size
Methode und man würde dann A().size()
anrufen, aber das ist weniger Python.
Ich habe versucht, die Länge in __iter__
und cachen es zu berechnen, so dass nachfolgende Aufrufe __len__
nicht wieder iter müssen aber list()
Anrufe __len__
ohne zu wiederholen beginnen so funktioniert es nicht.
Beachten Sie, dass ich in meinem Fall an sehr großen Datensammlungen arbeite, so dass das Zwischenspeichern aller Elemente keine Option ist.
Warum muss __len__ Implementierung __iter__ aufrufen? Empfängt __iter__ bei jedem Aufruf neue Daten? – Daniel
@Daniel Nein, es sind immer die gleichen Daten, aber es muss darüber iterieren, um seine Länge zu erhalten; wir wissen es nicht im voraus. – bfontaine
In welcher Phase von A wissen Sie? auf __init__? auf einer Setter-Methode? – Daniel