python - tutorial - ¿Cómo hacer iterable un objeto personalizado?
the django project (3)
También puede hacer una list
subclase:
class Direction(list):
def __init__(self, seq=[], id_=None):
list.__init__(self,seq)
self.id = id_ if id_ else id(self)
def __iter__(self):
it=list.__iter__(self)
next(it) # skip the first...
return it
d=Direction(range(10))
print(d) # all the data, no iteration
# [0, 1, 2, 3, 4]
print ('', ''.join(str(e) for e in d)) # ''for e in d'' is an iterator
# 1, 2, 3, 4
es decir, se salta el primero.
Funciona también para listas anidadas:
>>> d1=Direction([range(5), range(10,15), range(20,25)])
>>> d1
[range(0, 5), range(10, 15), range(20, 25)]
print(list(itertools.chain.from_iterable(d1)))
[10, 11, 12, 13, 14, 20, 21, 22, 23, 24]
Tengo una list
de objetos personalizados (la muestra está debajo).
Usando: list(itertools.chain.from_iterable(myBigList))
Quería "fusionar" todas las sublistas de stations
en una gran lista. Así que pensé que necesitaba hacer que mi clase personalizada fuera iterable.
Aquí hay una muestra de mi clase personalizada.
class direction(object) :
def __init__(self, id) :
self.id = id
self.__stations = list()
def __iter__(self):
self.__i = 0 # iterable current item
return iter(self.__stations)
def __next__(self):
if self.__i<len(self.__stations)-1:
self.__i += 1
return self.__stations[self.__i]
else:
raise StopIteration
Implementé __iter__
y __next__
pero parece que no funciona. Ni siquiera son llamados.
¿Alguna idea de lo que podría haber hecho mal?
Nota: Usando Python3.3
simplemente implementar __iter__
debería ser suficiente.
class direction(object) :
def __init__(self, id) :
self.id = id
self.__stations = list()
def __iter__(self):
#return iter(self.__stations[1:]) #uncomment this if you wanted to skip the first element.
return iter(self.__stations)
a = direction(1)
a._direction__stations= range(5)
b = direction(1)
b._direction__stations = range(10)
import itertools
print list(itertools.chain.from_iterable([a,b]))
print list(itertools.chain.from_iterable([range(5),range(10)]))
salida:
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Vea aquí por qué es _direction__stations
Cualquier identificador del formulario __spam (al menos dos guiones bajos principales, como máximo un guión bajo final) se reemplaza textualmente por classname _spam, donde classname es el nombre de clase actual con guiones bajos destacados.
__iter__
es lo que se llama cuando intenta iterar sobre una instancia de clase:
>>> class Foo(object):
... def __iter__(self):
... return (x for x in range(4))
...
>>> list(Foo())
[0, 1, 2, 3]
__next__
es lo que se llama en el objeto que se devuelve desde __iter__
(en python2.x, es el next
, no __next__
- Generalmente los __next__
a ambos para que el código funcione con cualquiera de ...):
class Bar(object):
def __init__(self):
self.idx = 0
self.data = range(4)
def __iter__(self):
return self
def __next__(self):
self.idx += 1
try:
return self.data[self.idx-1]
except IndexError:
self.idx = 0
raise StopIteration # Done iterating.
next = __next__ # python2.x compatibility.