[pyar] Diferencia entre iterar y yield, y el yield from
Joaquín Sorianello
listas en joac.com.ar
Mie Mayo 17 15:46:19 ART 2017
Cambiando un pelin tu segundo ejemplo:
def crash(*args, **kwargs):
raise Exception
class MyClass:
def __init__(self):
self.fh = open("foo.txt")
self.fh.close = crash
def __iter__(self):
yield from self.fh
mc = MyClass()
for line in mc:
print("L", line, end='')
if line == '33\n':
break
print("--")
for line in mc:
print("L", line, end='')
el output es:
L 11
L 22
L 33
Exception ignored in: <generator object MyClass.__iter__ at 0x7f5b2bec2518>
Traceback (most recent call last):
File "example2.py", line 12, in __iter__
yield from self.fh
File "example2.py", line 3, in crash
raise Exception
Exception:
--
L 44
L 55
L 66
Algo está pasando cuando salis del for con el iterador...
Fijate que si lo haces explicito:
class MyClass:
def __init__(self):
self.fh = open("foo.txt")
def __iter__(self):
yield from self.fh
mc = MyClass()
iterator = iter(mc)
for line in iterator:
print("L", line, end='')
if line == '33\n':
break
print("--")
for line in iterator:
print("L", line, end='')
Todo camina bien...
L 11
L 22
L 33
--
L 44
L 55
L 66
Claramente hay algo raro cuando se dealoca el iterador:
class MyClass:
def __init__(self):
self.fh = open("foo.txt")
def __iter__(self):
yield from self.fh
mc = MyClass()
iterator = iter(mc)
for line in iterator:
print("L", line, end='')
if line == '33\n':
break
del(iterator)
print("--")
for line in mc:
print("L", line, end='')
El problema de nuevo:
L 11
L 22
L 33
--
Traceback (most recent call last):
File "example2.py", line 19, in <module>
for line in mc:
File "example2.py", line 7, in __iter__
yield from self.fh
ValueError: I/O operation on closed file.
La respuesta, imagino está en las tripas de la implementacion en C de python.
Saludos!
2017-05-17 14:23 GMT-03:00 Facundo Batista <facundobatista en gmail.com>:
> Jugando con algo que se preguntó en el canal de IRC, llegué a este código:
>
>
> class MyClass:
> def __init__(self):
> self.fh = open("foo.txt")
>
> def __iter__(self):
> for x in self.fh:
> yield x
>
> mc = MyClass()
> for line in mc:
> print("L", line, end='')
> if line == '33\n':
> break
>
> print("--")
>
> for line in mc:
> print("L", line, end='')
>
>
> Teniendo en cuenta que...
>
> $ cat foo.txt
> 11
> 22
> 33
> 44
> 55
> 66
>
> Al ejecutar el código me sale:
>
> L 11
> L 22
> L 33
> --
> L 44
> L 55
> L 66
>
> ¡Perfecto!
>
> Pero ahora cambio el método __iter__ de la clase de arriba y dejo:
>
> def __iter__(self):
> yield from self.fh
>
> Cuando ejecuto el código me sale:
>
> L 11
> L 22
> L 33
> --
> Traceback (most recent call last):
> File "tfoo.py", line 32, in <module>
> for line in mc:
> File "tfoo.py", line 22, in __iter__
> yield from self.fh
> ValueError: I/O operation on closed file.
>
>
> Entonces, ¿cuando se cerró el archivo? ¿por qué?
>
> Gracias! Slds.
>
> --
> . Facundo
>
> Blog: http://www.taniquetil.com.ar/plog/
> PyAr: http://www.python.org/ar/
> Twitter: @facundobatista
> _______________________________________________
> Lista de Correo de PyAr - Python Argentina - pyar en python.org.ar
> Sitio web: http://www.python.org.ar/
>
> Para administrar la lista (o desuscribirse) entrar a http://listas.python.org.ar/listinfo/pyar
>
> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de Argentina - http://www.usla.org.ar
--
Joaquín Sorianello
A.K.A. Joac
@_joac
Más información sobre la lista de distribución pyar