iteradores - python funcion yield
¿Qué son exactamente iterador, iterable e iteración? (12)
Iterables tiene un método
__iter__
que__iter__
una instancia de un nuevo iterador cada vez.Los iteradores implementan un método
__next__
que devuelve ítems individuales y un método__iter__
que se devuelve aself
.Por lo tanto, los iteradores también son iterables, pero los iterables no son iteradores.
Luciano Ramalho, Pitón Fluido.
¿Cuáles son las definiciones más básicas de "iterable", "iterador" e "iteración en Python?
He leído múltiples definiciones, pero su significado exacto todavía no se hundirá.
¿Puede alguien ayudarme con la idea básica?
Antes de tratar con los iterables y el iterador, el factor principal que decide el iterable y el iterador es la secuencia.
Secuencia: Secuencia es la recopilación de datos.
Iterable: Iterable es el objeto de tipo de secuencia que admite el método Iter.
Iter method: Iter method toma la secuencia como entrada y crea un objeto conocido como iterador
Iterador: Iterador es el objeto que llama al método siguiente y transversal a través de la secuencia. Al llamar al método siguiente, devuelve el objeto que transversalmente está.
ejemplo:
x=[1,2,3,4]
x es una secuencia que consiste en la recopilación de datos
y=iter(x)
Al llamar a iter (x), devuelve un iterador solo cuando el objeto x tiene un método iter, de lo contrario, genera una excepción. Si devuelve el iterador, entonces y se asigna de esta forma:
y=[1,2,3,4]
Como y es un iterador, soporta el método next ()
Al llamar al siguiente método, devuelve los elementos individuales de la lista uno por uno.
Después de devolver el último elemento de la secuencia, si volvemos a llamar al siguiente método, se genera un error StopIteration
ejemplo:
>>> y.next()
1
>>> y.next()
2
>>> y.next()
3
>>> y.next()
4
>>> y.next()
StopIteration
Aquí está la explicación que utilizo para enseñar clases de Python:
Un ITERABLE es:
- cualquier cosa que se pueda pasar en bucle (es decir, se puede hacer un bucle en una cadena o archivo) o
- cualquier cosa que pueda aparecer en el lado derecho de un bucle
for x in iterable: ...
:for x in iterable: ...
o - cualquier cosa que pueda llamar con
iter()
que devolverá un ITERATOR:iter(obj)
o - un objeto que define
__iter__
que devuelve un ITERATOR nuevo, o puede tener un método__getitem__
adecuado para la búsqueda indexada.
Un ITERATOR es un objeto:
- con estado que recuerda dónde está durante la iteración,
- con un método
__next__
que:- Devuelve el siguiente valor en la iteración.
- actualiza el estado para que apunte al siguiente valor
- Señala cuando se hace levantando
StopIteration
- y eso es auto-iterable (lo que significa que tiene un método
__iter__
que devuelveself
).
Notas:
- El método
__next__
en Python 3 se deletrea anext
en Python 2, y - La función incorporada
next()
llama a ese método en el objeto que se le pasa.
Por ejemplo:
>>> s = ''cat'' # s is an ITERABLE
# s is a str object that is immutable
# s has no state
# s has a __getitem__() method
>>> t = iter(s) # t is an ITERATOR
# t has state (it starts by pointing at the "c"
# t has a next() method and an __iter__() method
>>> next(t) # the next() function returns the next value and advances the state
''c''
>>> next(t) # the next() function returns the next value and advances
''a''
>>> next(t) # the next() function returns the next value and advances
''t''
>>> next(t) # next() raises StopIteration to signal that iteration is complete
Traceback (most recent call last):
...
StopIteration
>>> iter(t) is t # the iterator is self-iterable
Aquí está mi hoja de trucos:
sequence
+
|
v
def __getitem__(self, index: int):
+ ...
| raise IndexError
|
|
| def __iter__(self):
| + ...
| | return <iterator>
| |
| |
+--> or <-----+ def __next__(self):
+ | + ...
| | | raise StopIteration
v | |
iterable | |
+ | |
| | v
| +----> and +-------> iterator
| ^
v |
iter(<iterable>) +----------------------+
|
def generator(): |
+ yield 1 |
| generator_expression +-+
| |
+-> generator() +-> generator_iterator +-+
Cuestionario: ¿Ves cómo ...
- Cada iterador es un iterable?
- ¿Se puede implementar el método
__iter__()
un objeto contenedor como un generador? - ¿
__next__
método iterable más un método__next__
no es necesariamente un iterador?
En Python todo es un objeto. Cuando se dice que un objeto es iterable, significa que puede recorrer (es decir, iterar) el objeto como una colección.
Las matrices, por ejemplo, son iterables. Puede recorrerlos con un bucle for, y pasar del índice 0 al índice n, siendo n la longitud del objeto de la matriz menos 1.
Los diccionarios (pares de clave / valor, también llamados arrays asociativos) también son iterables. Puedes pasar por sus llaves.
Obviamente los objetos que no son colecciones no son iterables. Un objeto bool, por ejemplo, solo tiene un valor, Verdadero o Falso. No es iterable (no tendría sentido que sea un objeto iterable).
Las respuestas anteriores son excelentes, pero como la mayoría de lo que he visto, no enfatice la distinción lo suficiente para las personas como yo.
Además, las personas tienden a ponerse "demasiado Pythonic" al colocar definiciones como "X es un objeto que tiene el __foo__()
" antes. Tales definiciones son correctas, se basan en la filosofía de tipificación de pato, pero el enfoque en los métodos tiende a interponerse cuando se trata de entender el concepto en su simplicidad.
Así que agrego mi versión.
En lenguaje natural,
- iteración es el proceso de tomar un elemento a la vez en una fila de elementos.
En Python,
iterable es un objeto que es, bueno, iterable, que en pocas palabras significa que puede usarse en iteración, por ejemplo, con un bucle
for
. ¿Cómo? Mediante el uso de iterador . Voy a explicar a continuación.... mientras que iterador es un objeto que define cómo realizar la iteración, específicamente cuál es el siguiente elemento. Es por eso que debe tener el método
next()
.
Los iteradores también son iterables, con la distinción de que su __iter__()
devuelve el mismo objeto ( self
), independientemente de si sus elementos han sido consumidos o no por las llamadas anteriores a next()
.
Entonces, ¿qué piensa el intérprete de Python cuando ve for x in obj:
statement?
Mira, un bucle
for
. Parece un trabajo para un iterador ... Consigamos uno. ... Hay un tipoobj
, así que preguntémosle."Sr.
obj
, ¿tiene su iterador?" (... llama aiter(obj)
, que llama aobj.__iter__()
, que felizmente entrega un nuevo iterador brillante_i
.)OK, eso fue fácil ... Comencemos iterando entonces. (
x = _i.next()
...x = _i.next()
...)
Como el Sr. obj
tuvo éxito en esta prueba (al tener cierto método para devolver un iterador válido), lo recompensamos con un adjetivo: ahora puede llamarlo "iterable Sr. obj
".
Sin embargo, en casos simples, normalmente no se beneficia de tener iterador e iterable por separado. Así que solo define un objeto, que también es su propio iterador. (A Python realmente no le importa que lo que _i
entregué por obj
no fuera tan brillante, sino solo el propio obj
).
Es por eso que en la mayoría de los ejemplos que he visto (y lo que me había confundido una y otra vez), puedes ver:
class IterableExample(object):
def __iter__(self):
return self
def next(self):
pass
en lugar de
class Iterator(object):
def next(self):
pass
class Iterable(object):
def __iter__(self):
return Iterator()
Sin embargo, hay casos en los que puede beneficiarse de tener un iterador separado de lo iterable, como cuando desea tener una fila de elementos, pero más "cursores". Por ejemplo, cuando desea trabajar con elementos "actuales" y "próximos", puede tener iteradores separados para ambos. O múltiples hilos que se extraen de una lista enorme: cada uno puede tener su propio iterador para recorrer todos los elementos. Vea @glglgl''s respuestas de @Raymond''s y @glglgl''s arriba.
Imagina lo que podrías hacer:
class SmartIterableExample(object):
def create_iterator(self):
# An amazingly powerful yet simple way to create arbitrary
# iterator, utilizing object state (or not, if you are fan
# of functional), magic and nuclear waste--no kittens hurt.
pass # don''t forget to add the next() method
def __iter__(self):
return self.create_iterator()
Notas:
Repetiré de nuevo: el iterador no es iterable . El iterador no se puede usar como "fuente" en el bucle
for
. Lofor
necesita principalmente el bucle es__iter__()
(que devuelve algo connext()
).Por supuesto,
for
no es el único bucle de iteración, así que lo anterior también se aplica a algunas otras construcciones (while
...).El
next()
iterador puede lanzar StopIteration para detener la iteración. Sin embargo, no tiene que hacerlo, puede iterar para siempre o usar otros medios.En el "proceso de pensamiento" anterior,
_i
realmente no existe. He inventado ese nombre.Hay un pequeño cambio en Python 3.x: el método
next()
(no el incorporado) ahora se debe llamar__next__()
. Sí, debería haber sido así todo el tiempo.También puede pensarlo así: iterable tiene los datos, el iterador extrae el siguiente elemento
Descargo de responsabilidad: no soy desarrollador de ningún intérprete de Python, por lo que realmente no sé qué "piensa" el intérprete. Las reflexiones anteriores son únicamente una demostración de cómo entiendo el tema a partir de otras explicaciones, experimentos y experiencias de la vida real de un novato de Python.
No creo que puedas hacerlo mucho más simple que la documentation , sin embargo, lo intentaré:
- Iterable es algo que puede ser iterado . En la práctica, usualmente significa una secuencia, por ejemplo, algo que tiene un principio y un final y alguna forma de revisar todos los elementos que contiene.
Puede pensar en Iterator como un pseudo-método auxiliar (o pseudo-atributo) que le da (o retiene) el siguiente (o primer) elemento en el iterable . (En la práctica, es solo un objeto que define el método
next()
)La iteración es probablemente mejor explicada por la definición de Merriam-Webster de la palabra :
b: la repetición de una secuencia de instrucciones de computadora un número específico de veces o hasta que se cumpla una condición - compare la recursión
No sé si ayuda a alguien, pero siempre me gusta visualizar conceptos en mi cabeza para entenderlos mejor. Entonces, como tengo un hijo pequeño, visualizo el concepto iterativo / iterador con ladrillos y papel blanco.
Supongamos que estamos en el cuarto oscuro y en el piso tenemos ladrillos para mi hijo. Ladrillos de diferente tamaño, color, no importa ahora. Supongamos que tenemos 5 ladrillos como esos. Esos 5 ladrillos se pueden describir como un objeto , digamos kit de ladrillos . Podemos hacer muchas cosas con este kit de ladrillos: podemos tomar uno y luego tomar el segundo y luego el tercero, podemos cambiar los lugares de ladrillos, poner el primer ladrillo por encima del segundo. Podemos hacer muchos tipos de cosas con esos. Por lo tanto, este kit de ladrillos es un objeto o secuencia iterable , ya que podemos atravesar cada ladrillo y hacer algo con él. Solo podemos hacerlo como mi pequeño hijo: podemos jugar con un ladrillo a la vez . Así que de nuevo me imagino que este kit de ladrillos es un iterable .
Ahora recuerda que estamos en el cuarto oscuro. O casi a oscuras. El problema es que no vemos claramente esos ladrillos, qué color son, qué forma, etc. Entonces, incluso si queremos hacer algo con ellos, también conocido como iterar a través de ellos , no sabemos qué y cómo, porque es demasiado oscuro.
Lo que podemos hacer es acercarnos al primer ladrillo, como elemento de un kit de ladrillos, podemos poner un trozo de papel blanco fluorescente para que podamos ver dónde está el primer elemento de ladrillo. Y cada vez que sacamos un ladrillo de un kit, reemplazamos el trozo de papel blanco por el siguiente ladrillo para poder ver eso en el cuarto oscuro. Esta hoja blanca de papel no es más que un iterador . También es un objeto . Pero un objeto con el que podemos trabajar y jugar con elementos de nuestro objeto iterable: el juego de ladrillos.
Por cierto, eso explica mi error inicial cuando probé lo siguiente en un IDLE y obtuve un TypeError:
>>> X = [1,2,3,4,5]
>>> next(X)
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
next(X)
TypeError: ''list'' object is not an iterator
Lista X aquí estaba nuestro kit de ladrillos, pero NO un pedazo de papel blanco. Necesitaba encontrar un iterador primero:
>>> X = [1,2,3,4,5]
>>> bricks_kit = [1,2,3,4,5]
>>> white_piece_of_paper = iter(bricks_kit)
>>> next(white_piece_of_paper)
1
>>> next(white_piece_of_paper)
2
>>>
No sé si ayuda, pero me ayudó. Si alguien pudiera confirmar / corregir la visualización del concepto, estaría agradecido. Me ayudaría a aprender más.
Un iterable es un objeto que tiene un __iter__()
. Posiblemente puede repetirse varias veces, como list()
sy tuple()
s.
Un iterador es el objeto que itera. Se devuelve mediante un __iter__()
, se devuelve a sí mismo a través de su propio __iter__()
y tiene un método next()
( __next__()
en 3.x).
La iteración es el proceso de llamar a este next()
resp. __next__()
hasta que StopIteration
.
Ejemplo:
>>> a = [1, 2, 3] # iterable
>>> b1 = iter(a) # iterator 1
>>> b2 = iter(a) # iterator 2, independent of b1
>>> next(b1)
1
>>> next(b1)
2
>>> next(b2) # start over, as it is the first call to b2
1
>>> next(b1)
3
>>> next(b1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> b1 = iter(a) # new one, start over
>>> next(b1)
1
Iterable : - algo que es iterable es iterable; me gusta secuencias como listas, cadenas, etc. También tiene el __getItem__()
o una función iter()
que devuelve un iterador.
Iterador : - Cuando obtenemos el objeto iterador del método iter()
de iterable; Llamamos al __next__()
(en python3) o simplemente next()
(en python2) para obtener los elementos uno por uno. Esta clase o instancia de esta clase se llama un iterador.
De los documentos: -
El uso de iteradores impregna y unifica Python. Detrás de escena, la instrucción for llama a iter()
en el objeto contenedor. La función devuelve un objeto iterador que define el método __next__()
que accede a los elementos en el contenedor de uno en uno. Cuando no hay más elementos, __next__()
genera una excepción StopIteration que le dice al bucle for que termine. Puede llamar al __next__()
usando la función incorporada next()
; Este ejemplo muestra cómo funciona todo:
>>> s = ''abc''
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
''a''
>>> next(it)
''b''
>>> next(it)
''c''
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
next(it)
StopIteration
Ex de una clase: -
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
>>> rev = Reverse(''spam'')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
... print(char)
...
m
a
p
s
Iteración es un término general para tomar cada elemento de algo, uno tras otro. Cada vez que use un bucle, explícito o implícito, para repasar un grupo de elementos, eso es iteración.
En Python, iterable e iterador tienen significados específicos.
Un iterable es un objeto que tiene un método __iter__
que devuelve un iterador , o que define un método __getitem__
que puede tomar índices secuenciales comenzando desde cero (y genera un IndexError
cuando los índices ya no son válidos). Por lo tanto, un objeto iterable es un objeto del que puede obtener un iterador .
Un iterador es un objeto con un método next
(Python 2) o __next__
(Python 3).
Siempre que use un bucle for
, un map
, una lista de comprensión, etc. en Python, se llama automáticamente al next
método para obtener cada elemento del iterador , y así pasar por el proceso de iteración .
Un buen lugar para comenzar a aprender sería la sección de iteradores del tutorial y la sección de tipos de iteradores de la página de tipos estándar . Después de comprender los conceptos básicos, pruebe la sección de iteradores del CÓMO de programación funcional .
iterable = [1, 2]
iterator = iter(iterable)
print(iterator.__next__())
print(iterator.__next__())
asi que,
iterable
es un objeto que puede ser colocado en bucle . por ejemplo, lista, cadena, tupla etc.el uso de la función
iter
en nuestro objetoiterable
devolverá un objeto iterador.ahora este objeto iterador tiene un método llamado
__next__
(en Python 3, o simplemente elnext
en Python 2) mediante el cual puede acceder a cada elemento de iterable.
Así, el CÓDIGO DE SALIDA DE ARRIBA SERÁ:
1
2