¿Cómo implementar una clase mínima que se comporte como una secuencia en Python?

Estoy buscando un ejemplo mínimo de una clase que imite una secuencia inmutable en Python.

class MySequence() ... a = MySequence() len(a) for i in a: pass a[0] 

¿Cuáles son los métodos que se deben implementar?

Si solo desea poder iterar sobre su secuencia, solo necesita implementar el método __iter__ devolviendo un iterable. La forma más sencilla de hacerlo es crear un generador utilizando la statement de yield .

 class MySequence(object): def __iter__(self): yield 1 yield 2 yield 3 for x in MySequence(): print x # prints 1, then 2, then 3 

Sin embargo, esto no habilitará cosas como MySequence()[1] . Para eso necesita implementar el método __getitem__ , y probablemente debería implementar también __len__ .

 class MySequence(object): def __len__(self): return 3 def __getitem__(self, key): if key == 0: return 1 elif key == 1: return 2 elif key == 2: return 3 else: raise IndexError() s = new MySequence() for i in range(len(s)): print s[i] # prints 1, then 2, then 3 for x in s: print x # prints 1, then 2, then 3 

Note que omití __iter__ . Mientras __getitem__ IndexError un IndexError cuando intenta obtener un valor que está fuera de límites, Python puede usarlo para la iteración. (Todavía podría incluir __iter__ si quisiera ser más claro o quisiera un comportamiento de iteración no estándar).

Agregando a la respuesta de @ Jeremy: Un cheque popular de que un valor es una secuencia general es usar isinstance(value, collections.Sequence) .

Para que esto sea cierto para su tipo, debe heredar de las collections.Sequence . __index__ , y esto en realidad proporciona el iterador (y algunas otras funciones útiles) como mixins, siempre que proporcione las funciones __len__ e __index__ .

Tomando prestado de la respuesta de @ Jeremy, una clase de ejemplo sería:

 import collections class MySequence(collections.Sequence): def __len__(self): return 3 def __getitem__(self, key): if key == 0: return 1 elif key == 1: return 2 elif key == 2: return 3 else: raise IndexError() 

Ejemplos de uso:

 s = MySequence() for i in range(len(s)): print s[i] # prints 1, then 2, then 3 for x in s: print x # prints 1, then 2, then 3 print isinstance(s, collections.Sequence) # prints True print 1 in s # prints True print list(reversed(s)) # prints [3, 2, 1]