Iteradores y generadores son una gran parte del lenguaje Python. Es posible que no entendamos estos dos conceptos, pero ya hemos tenido contacto en el estudio anterior. Por ejemplo, usar for...in
recorrer una lista, diccionario, tupla, es usar un iterador.
Objeto iterable (iterable)
Este concepto se ha aprendido antes y se menciona aquí para comprender mejor el iterador. Literalmente, los objetos iterativos tienen mucho que ver con los iteradores. Los iteradores actúan sobre objetos iterables, devolviendo los elementos del objeto iterable uno por uno. Es decir, un objeto que puede ser atravesado por un bucle for
puede llamarse un objeto iterable. Entre los tipos de datos incorporados en Python, los objetos iterables son: str, list, tuple, dict, set
. Estas estructuras de datos se utilizan para almacenar otros objetos, también conocidos como "contenedores".
Iterador
for
lista de recorrido de bucles for
(tomamos una lista como ejemplo, tuplas y diccionarios, etc.) está detrás del iterador. Python tiene dos funciones integradas, iter()
y next()
que convierten estas visualizaciones de objetos iterables en iteraciones. Y atravesar. Echa un vistazo al siguiente código:
In [1]: ll = [1,2,3]
In [2]: for n in ll:
...: print(n)
...:
1
2
3
In [3]: itr = iter(ll)
In [4]: itr?
Type: list_iterator
String form: <list_iterator object at 0x7fc0483c9828>
Docstring: <no docstring>
In [5]: next(itr)
Out[5]: 1
In [6]: next(itr)
Out[6]: 2
In [7]: next(itr)
Out[7]: 3
In [8]: next(itr)
----------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-8-6693cc261707> in <module>
----> 1 next(itr)
StopIteration:
A través de la función incorporada iter()
, podemos obtener el iterador del objeto list (en realidad es la llamada a ll.__iter__()
), y obtener un objeto list_iterator
; luego podemos iterar a través de la iteración con la función incorporada next()
(en realidad se llama ll.__next__()
). Cada llamada a next()
obtiene un elemento de ll
, que devuelve los elementos de ll
en orden, es decir, el mecanismo iterador posiciona el elemento actual. Cuando se recorre el elemento, se StopIteration
una excepción StopIteration
. A partir de ese momento, el iterador que obtenemos inicialmente no puede repetirse porque se ha repetido hasta el final.
A través del ejemplo anterior, podemos ver las pistas de algunos iteradores. De hecho, el iterador es el __iter__()
que define el __iter__()
para devolver un __next__()
con el __next__()
. De acuerdo con esta definición, no utilizamos funciones integradas, pero usamos __iter__()
y __next__()
para iterar sobre el objeto de lista:
In [9]: ll
Out[9]: [1, 2, 3]
In [10]: itr = ll.__iter__()
In [11]: itr
Out[11]: <list_iterator at 0x7fc048dcdcc0>
In [12]: itr.__next__()
Out[12]: 1
In [13]: itr.__next__()
Out[13]: 2
In [14]: itr.__next__()
Out[14]: 3
In [15]: itr.__next__()
----------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-15-fc6e27a9fb4c> in <module>
----> 1 itr.__next__()
StopIteration:
Como puede ver, esto logra el mismo efecto que las funciones incorporadas iter()
y next()
. De hecho, la función incorporada iter()
llama al método __iter__()
del iterador, y next()
llama al método __next__()
del iterador.
Comprenda el mecanismo interno del iterador (llamado "protocolo del iterador"), podemos agregar el comportamiento del iterador en la clase personalizada:
In [21]: class LessThan:
...: '''Un iterador que atraviesa un entero positivo más pequeño que un entero dado'''
...: def __init__(self, n):
...: self.n = n
...:
...: def __iter__(self):
...: return self
...:
...: def __next__(self):
...:
...: if self.n == 0:
...: raise StopIteration
...: self.n -= 1
...: return self.n
In [23]: lt = LessThan(5)
In [24]: lt
Out[24]: <__main__.LessThan at 0x7fc048d3acc0>
In [25]: iter(lt)
Out[25]: <__main__.LessThan at 0x7fc048d3acc0>
In [26]: for n in lt:
...: print(n, end=' ')
...:
4 3 2 1 0
lt
es un objeto de nuestra clase personalizada LessThan
. Puede obtener su iterador a través de la función incorporada iter()
. Son exactamente iguales, tanto <__main__.LessThan at 0x7fc048d3acc0>
, porque la función incorporada y iter()
llamadas. Este es el método lt.__iter__()
, y este método se devuelve a sí mismo (con el __next__()
).
Resumen
(1) Objetos iterables:
Los objetos que pueden atravesarse por un bucle for
son todos objetos iterables.Esencialmente, un objeto que define un __iter__()
o un método __getitem__()
es un objeto iterable.
(2) Iterador:
El objeto que define el __next__()
es un iterador. Una iteración de iterador causará una excepción de Stopiteration
al final.
(2) Funciones incorporadas iter()
y next()
iter()
actúa en iteradores para objetos iterables; next()
itera sobre iteradores.
(3) La clase personalizada clase personalizada define el __iter__()
y el método __next__()
para implementar el iterador;
留言
張貼留言