Pregunta

Estoy tratando de implementar la funcionalidad de la rebanada para una clase que estoy haciendo que crea una representación vectorial.

Tengo este código hasta ahora, que creo que va a aplicar correctamente el corte, pero cada vez que hago una llamada como v[4] donde V es una pitón de vectores devuelve un error 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 ambos índices lisos y rebanar.

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]
¿Fue útil?

Solución

El método __getitem__() recibirá un objeto slice cuando se corta el objeto. Basta con mirar el start, stop, y los miembros step del objeto slice con el fin de obtener los componentes de la división.

>>> 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')

Otros consejos

Tengo una lista de "sintético" (uno donde los datos es mayor de lo que se desee crear en la memoria) y mi aspecto __getitem__ como esta:

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 corte no devuelve el mismo tipo, que es un no-no, pero funciona para mí.

¿Cómo definir la clase GetItem para manejar tanto los índices de fricción y corte en rodajas?

objetos de división se crea automáticamente cuando se utiliza una coma en la notación de subíndice - y que es lo que se pasa a __getitem__. Uso isinstance para comprobar si tiene un objeto de división:

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

Python 2, tenga en cuenta:

En Python 2, hay un método en desuso que puede que tenga que reemplazar cuando la subclasificación de algunos tipos internos.

Desde el modelo de datos de documentación :

object.__getslice__(self, i, j)

Deprecated desde la versión 2.0: rebanada Soporte objetos como parámetros al método __getitem__(). (Sin embargo, los tipos incorporados en CPython actualmente todavía aplicar __getslice__(). Por lo tanto, hay que anularlo en las clases derivadas en la aplicación de corte.)

Esto se ha ido en Python 3.

La forma correcta de hacer esto es tener __getitem__ toma un parámetro, que puede ser un número, o un objeto de división.

Vea:

http://docs.python.org/library/functions.html#slice

http://docs.python.org/reference/datamodel.html#object.__getitem__

Para extender la respuesta de Aarón, para cosas como numpy, se puede hacer el corte en lonchas multidimensional mediante la comprobación para ver si es un given 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)))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top