example - Python: implementando slicing en__getitem__
python class (5)
Estoy tratando de implementar la funcionalidad de corte para una clase que estoy creando que crea una representación vectorial.
Tengo este código hasta el momento, que creo que implementará correctamente el segmento, pero cada vez que hago una llamada como v[4]
donde v es un vector python devuelve un error acerca de no tener suficientes parámetros. Así que estoy tratando de encontrar la manera de definir el método especial getitem
en mi clase para manejar tanto índices simples como segmentación.
def __getitem__(self, start, stop, step):
index = start
if stop == None:
end = start + 1
else:
end = stop
if step == None:
stride = 1
else:
stride = step
return self.__data[index:end:stride]
¿Cómo se define la clase getitem para manejar tanto índices simples como slicing?
Los objetos de corte se crean automáticamente cuando usa dos puntos en la notación de subíndice, y eso es lo que se pasa a __getitem__
. Use isinstance
para verificar si tiene un objeto slice:
from __future__ import print_function
class Sliceable(object):
def __getitem__(self, given):
if isinstance(given, slice):
# do your handling for a slice object:
print(given.start, given.stop, given.step)
else:
# Do your handling for a plain index
print(given)
Ejemplo de uso:
>>> sliceme = Sliceable()
>>> sliceme[1]
1
>>> sliceme[2]
2
>>> sliceme[:]
None None None
>>> sliceme[1:]
1 None None
>>> sliceme[1:2]
1 2 None
>>> sliceme[1:2:3]
1 2 3
>>> sliceme[:2:3]
None 2 3
>>> sliceme[::3]
None None 3
>>> sliceme[::]
None None None
>>> sliceme[:]
None None None
El método __getitem__()
recibirá un objeto de slice
cuando se slice
el objeto. Simplemente observe los miembros start
, stop
y step
del objeto slice
para obtener los componentes del segmento.
>>> class C(object):
... def __getitem__(self, val):
... print val
...
>>> c = C()
>>> c[3]
3
>>> c[3:4]
slice(3, 4, None)
>>> c[3:4:-2]
slice(3, 4, -2)
>>> c[():1j:''a'']
slice((), 1j, ''a'')
Para extender la respuesta de Aaron, para cosas como numpy
, puedes hacer un corte multidimensional verificando si se given
una tuple
:
class Sliceable(object):
def __getitem__(self, given):
if isinstance(given, slice):
# do your handling for a slice object:
print("slice", given.start, given.stop, given.step)
elif isinstance(given, tuple):
print("multidim", given)
else:
# Do your handling for a plain index
print("plain", given)
sliceme = Sliceable()
sliceme[1]
sliceme[::]
sliceme[1:, ::2]
`` `
Salida:
(''plain'', 1)
(''slice'', None, None, None)
(''multidim'', (slice(1, None, None), slice(None, None, 2)))
Tengo una lista "sintética" (una donde los datos son más grandes de lo que quisiera crear en la memoria) y mi __getitem__
ve así:
def __getitem__( self, key ) :
if isinstance( key, slice ) :
#Get the start, stop, and step from the slice
return [self[ii] for ii in xrange(*key.indices(len(self)))]
elif isinstance( key, int ) :
if key < 0 : #Handle negative indices
key += len( self )
if key < 0 or key >= len( self ) :
raise IndexError, "The index (%d) is out of range."%key
return self.getData(key) #Get the data from elsewhere
else:
raise TypeError, "Invalid argument type."
El sector no devuelve el mismo tipo, que es un no-no, pero funciona para mí.