¿Por qué definir __getitem__ en una clase lo hace iterable en python?

votos
45

¿Por qué la definición de __getitem__ en una clase lo hace iterable?

Por ejemplo, si escribo:

class b:
  def __getitem__(self, k):
    return k

cb = b()

for k in cb:
  print k

Obtengo el resultado:

0
1
2
3
4
5
6
7
8
...

Realmente esperaría ver un error devuelto por para k en cb:

Publicado el 29/05/2009 a las 16:22
fuente por usuario
En otros idiomas...                            


6 respuestas

votos
3

Debido a que cb[0]es el mismo que cb.__getitem__(0). Ver la documentación de Python sobre esto.

Respondida el 29/05/2009 a las 16:26
fuente por usuario

votos
5

Métodos especiales, como __getitem__agregar comportamientos especiales a los objetos, incluida la iteración.

http://docs.python.org/reference/datamodel.html#object. obtiene el objeto

"para bucles, se espera que un IndexError se alce para los índices ilegales para permitir la detección adecuada del final de la secuencia".

Levante IndexError para señalar el final de la secuencia.

Tu código es básicamente equivalente a:

i = 0
while True:
    try:
        yield object[i]
        i += 1
    except IndexError:
        break

Donde objeto es lo que está iterando en el ciclo for.

Respondida el 29/05/2009 a las 16:28
fuente por usuario

votos
42

Si echas un vistazo a los iteradores que definen PEP234 , dice:

1. An object can be iterated over with "for" if it implements
   __iter__() or __getitem__().

2. An object can function as an iterator if it implements next().
Respondida el 29/05/2009 a las 16:29
fuente por usuario

votos
48

El soporte de Iteration para __getitem__puede verse como una "característica heredada" que permitió una transición más suave cuando PEP234 introdujo la iterabilidad como concepto principal. Solo se aplica a las clases sin __iter__cuyos __getitem__acepta enteros 0, 1, & c, y aumenta IndexErroruna vez que el índice es demasiado alto (si alguna vez), normalmente las clases de "secuencia" codificadas anteriormente __iter__aparecieron (aunque nada impide codificar nuevas clases de esta manera).

Personalmente, prefiero no confiar en esto en un código nuevo, aunque no está en desuso ni se va a ir (funciona bien en Python 3 también), así que esto es solo cuestión de estilo y gusto ("explícito es mejor que implícito", por lo Prefiero apoyar explícitamente la iterabilidad en lugar de confiar en su __getitem__apoyo implícito para mí, pero no un bigge).

Respondida el 29/05/2009 a las 16:37
fuente por usuario

votos
20

__getitem__es anterior al protocolo del iterador, y en el pasado era la única forma de hacer las cosas iterables. Como tal, todavía es compatible como un método de iteración. Esencialmente, el protocolo para la iteración es:

  1. Verifica un __iter__método. Si existe, use el nuevo protocolo de iteración.

  2. De lo contrario, intente llamar __getitem__con valores enteros sucesivamente más grandes hasta que provoque IndexError.

(2) solía ser la única forma de hacerlo, pero tenía la desventaja de que suponía más de lo necesario para admitir solo iteraciones. Para admitir la iteración, tenía que admitir el acceso aleatorio, que era mucho más costoso para cosas como archivos o secuencias de red, donde ir hacia adelante era fácil, pero retroceder exigiría almacenar todo. __iter__la iteración permitida sin acceso aleatorio, pero dado que el acceso aleatorio usualmente permite la iteración de todos modos, y porque la ruptura de la compatibilidad hacia atrás sería mala, __getitem__aún es compatible.

Respondida el 29/05/2009 a las 16:38
fuente por usuario

votos
5

Esto es así por razones históricas. Antes de Python 2.2 __getitem__ era la única forma de crear una clase que pudiera repetirse con el ciclo for. En 2.2 se agregó el protocolo __iter__ pero para mantener la compatibilidad con versiones anteriores __getitem__ aún funciona en bucles.

Respondida el 29/05/2009 a las 16:38
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more