Il contesto originale di questo bug è un pezzo di codice troppo grande per essere inserito in una domanda come questa. Ho dovuto ridurre questo codice a uno snippet minimo che mostra ancora il bug. Questo è il motivo per cui il codice mostrato di seguito è un po 'bizzarro.Fastidioso bug del generatore
Nel codice seguente, la classe Foo
può essere considerata un modo complesso per ottenere qualcosa come xrange
.
class Foo(object):
def __init__(self, n):
self.generator = (x for x in range(n))
def __iter__(self):
for e in self.generator:
yield e
Infatti, Foo
sembra comportarsi molto simile xrange
:
for c in Foo(3):
print c
# 0
# 1
# 2
print list(Foo(3))
# [0, 1, 2]
Ora, la sottoclasse Bar
di Foo
aggiunge solo un metodo __len__
:
class Bar(Foo):
def __len__(self):
return sum(1 for _ in self.generator)
Bar
comporta come Foo
se utilizzato in un for
-loop:
for c in Bar(3):
print c
# 0
# 1
# 2
MA:
print list(Bar(3))
# []
mia ipotesi è che, nella valutazione della list(Bar(3))
, il metodo di Bar(3)
__len__
viene sempre chiamato, usando così il generatore.
(Se questa ipotesi è corretta, la chiamata a Bar(3).__len__
è necessario, dopo tutto, list(Foo(3))
produce il risultato corretto anche se Foo
non ha un metodo __len__
.)
Questa situazione è fastidioso: non c'è nessuna buona ragione per list(Foo(3))
e list(Bar(3))
per produrre risultati diversi.
E 'possibile fissare Bar
(senza, ovviamente, per liberarsi del suo metodo di __len__
) in modo tale che i rendimenti list(Bar(3))
[0, 1, 2]
?
Che cosa succede se il generatore è infinito? – thefourtheye
@thefourtheye: poiché, AFAICT, lo scenario che proponi non può accadere nel codice presentato, non so come interpretare la tua domanda. – kjo
Hai ragione che 'list (Bar (3))' chiama '__len__' (che puoi vedere semplicemente aggiungendo un'istruzione print al tuo metodo len). La mia domanda è: sai che i generatori possono essere esauriti e dovrebbero essere usati solo una volta, quindi invece di memorizzare l'oggetto generatore stesso, perché non progettare la tua classe per sapere come generare uno_ su richiesta? –