Sto sperimentando 2 funzioni che emulano il codice zip
integrato in Python 2.xe 3.x. Il primo restituisce una lista (come in Python 2.x) e la seconda è una funzione generatore che restituisce un pezzo del suo set di risultati alla volta (come in Python 3.x):L'espressione del generatore causa l'interruzione di Python
def myzip_2x(*seqs):
its = [iter(seq) for seq in seqs]
res = []
while True:
try:
res.append(tuple([next(it) for it in its])) # Or use generator expression?
# res.append(tuple(next(it) for it in its))
except StopIteration:
break
return res
def myzip_3x(*seqs):
its = [iter(seq) for seq in seqs]
while True:
try:
yield tuple([next(it) for it in its]) # Or use generator expression?
# yield tuple(next(it) for it in its)
except StopIteration:
return
print(myzip_2x('abc', 'xyz123'))
print(list(myzip_3x([1, 2, 3, 4, 5], [7, 8, 9])))
Questo funziona bene e dà l'uscita prevista del zip
built-in:
[('a', 'x'), ('b', 'y'), ('c', 'z')]
[(1, 7), (2, 8), (3, 9)]
Poi ho pensato di sostituire l'elenco di comprensione nei tuple()
chiamate con il suo (quasi) espressione equivalente del generatore, eliminando le parentesi quadre []
(perché crea una lista temporanea usando la comprensione quando il generatore dovrebbe andare bene per l'exp iterabile ect by tuple()
, giusto?)
Tuttavia, questo causa l'interruzione di Python. Se l'esecuzione non viene interrotta utilizzando CtrlC (in IDLE su Windows), alla fine si fermerà dopo alcuni minuti con un'eccezione (prevista) MemoryError
.
Il debug del codice (utilizzando PyScripter per esempio) ha rivelato che l'eccezione StopIteration
non viene mai sollevata quando si utilizza l'espressione del generatore. La prima chiamata esempio di cui sopra per myzip_2x()
continua ad aggiungere tuple vuote res
, mentre il secondo esempio chiamata a myzip_3x()
produce tuple (1, 7)
, (2, 8)
, (3, 9)
, (4,)
, (5,)
, ()
, ()
, ()
, ...
.
Mi manca qualcosa?
E una nota finale: lo stesso comportamento appeso appare se its
diventa un generatore (utilizzando its = (iter(seq) for seq in seqs)
) nella prima linea di ciascuna funzione (quando Lista comprehensions vengono utilizzati nella chiamata tuple()
).
Edit:
Grazie @Blckknght per la spiegazione, avevi ragione. This message fornisce maggiori dettagli su ciò che sta accadendo utilizzando un esempio simile alla funzione generatore di cui sopra. In conclusione, l'utilizzo di espressioni generatrici come questo funziona solo in Python 3.5+ e richiede l'istruzione from __future__ import generator_stop
nella parte superiore del file e la modifica di StopIteration
con RuntimeError
sopra (di nuovo, quando si utilizzano le espressioni del generatore anziché le liste di comprensione).
Edit 2:
Quanto alla nota finale sopra: se its
diventa un generatore (usando its = (iter(seq) for seq in seqs)
) sosterrà solo un'iterazione - perché generatori sono one-shot iteratori. Pertanto si esaurisce la prima volta che si esegue il ciclo while e nei cicli successivi si ottengono solo tuple vuote.
Posso confermare la tua ipotesi eseguendo codici al di fuori di qualsiasi loop o funzione. –
Grazie per una buona spiegazione concettuale. – John