¿Por qué un iterador de Python necesita un método iter que simplemente se devuelva a sí mismo?

Entiendo que la norma dice que sí, pero estoy tratando de encontrar la razón subyacente para esto.

Si simplemente siempre vuelve a self ¿cuál es la necesidad de ello?

Claramente, siempre tiene acceso al objeto ya que está invocando iter en ese objeto, así que, ¿cuál es la necesidad de tenerlo?

Imagina que quieres escribir código que se repita sobre cualquier tipo de iterable. Normalmente, solo escribes for una statement o comprensión, pero en lugar de eso hacemos explícitamente lo que hace debajo de las portadas, para hacer las cosas más obvias:

 i = iter(iterable) while True: try: val = next(i) except StopIteration: break else: do_stuff(val) 

Si no hace esa primera línea, su código no funcionará con listas, cadenas, tuplas o cualquier otra cosa que no sea iterador.

Pero si hace esa primera línea, bueno, es mejor que iter(iterable) devuelva un iterador, o su código no funcionará con los iteradores.


Quizás te preguntes por qué iter no podría hacer lo correcto sin esto. Después de todo, tiene magia para crear un iterador cuando se le da un objeto que tiene un __len__ y un __getitem__ pero no __iter__ , entonces, ¿por qué no podría tener magia para devolver su argumento si tiene un __next__ pero no __iter__ ? Ese es un problema de diseño de lenguaje, pero en general, Python intenta tener la menor magia posible. La magia para hacer que las secuencias no fueran totalmente iterables era necesaria porque tales secuencias existían (en un código de terceros generalizado) antes de que el protocolo de iteración se agregara al lenguaje, y sería demasiado difícil de eliminar por el pequeño beneficio de simplificar las cosas.

for bucles debería funcionar con iterables, así que for i in something: llama automáticamente a iter(something) para obtener un iterador e itera sobre dicho iterador. Ahora bien, si los iteradores no fueran iterables también (es decir, no definió __iter__ ), no se podría usar for bucles con iteradores, es decir:

 items = [1, 2, 3] # this would work for item in items: pass # this wouldn't it = iter(items) for item in it: pass 

Por lo tanto, los iteradores deben ser iterables también. La alternativa, “detectar de alguna manera” los iteradores y no llamarlos a un iterador, es intrépida y frágil (¿cómo decidiría eso?).

Es así for bucles y otros códigos que necesitan trabajar con iterables pueden incondicionalmente invocar iter sobre lo que están iterando, en lugar de tratar los iteradores y otros iterables por separado. En particular, los no iteradores pueden tener razonablemente un método llamado a next , y queremos poder distinguirlos de los iteradores.

__iter__() está diseñado para devolver un iterador sobre el objeto. ¿Qué es un iterador sobre un objeto que ya es un iterador? self , por supuesto.