J'essaie d'implémenter la fonctionnalité de tranche pour une classe que je crée qui crée une représentation vectorielle.
J'ai ce code jusqu'à présent, qui, je crois, implémentera correctement la tranche, mais chaque fois que je fais un appel comme v[4]
où v est un vecteur python renvoie une erreur sur le manque de paramètres. J'essaie donc de comprendre comment définir la méthode spéciale getitem
dans ma classe pour gérer à la fois des index simples et des tranches.
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]
La méthode __getitem__()
recevra un objet slice
lorsque l'objet sera découpé. Regardez simplement les membres start
, stop
et step
de l'objet slice
afin d'obtenir les composants de la tranche.
>>> 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')
J'ai une liste "synthétique" (une où les données sont plus grandes que celles que vous voudriez créer en mémoire) et mon __getitem__
ressemble à ça:
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."
La tranche ne renvoie pas le même type, ce qui est non-non, mais cela fonctionne pour moi.
Comment définir la classe getitem pour gérer à la fois les index simples et le découpage?
Les objets Slice sont automatiquement créés lorsque vous utilisez deux points dans la notation en indice - et ça est ce qui est passé à __getitem__
. Utilisez isinstance
pour vérifier si vous avez un objet tranche:
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)
Exemple d'utilisation:
>>> 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
Dans Python 2, il existe une méthode obsolète que vous devrez peut-être remplacer lors du sous-classement de certains types intégrés.
De la documentation du modèle de données :
object.__getslice__(self, i, j)
Déconseillé depuis la version 2.0: Prise en charge des objets slice en tant que paramètres de la méthode
__getitem__()
. (Cependant, les types intégrés de CPython implémentent actuellement__getslice__()
. Par conséquent, vous devez le remplacer dans les classes dérivées lors de l'implémentation du découpage.)
Cela a disparu dans Python 3.
La bonne façon de procéder consiste à avoir __getitem__
prend un paramètre, qui peut être soit un nombre, soit un objet tranche.
Voir:
http://docs.python.org/library/functions.html#slice
http://docs.python.org/reference/datamodel.html#object.__getitem__
Pour étendre la réponse d'Aaron, pour des choses comme numpy
, vous pouvez faire un découpage multidimensionnel en vérifiant si given
est un 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]
`` ''
Sortie:
('plain', 1)
('slice', None, None, None)
('multidim', (slice(1, None, None), slice(None, None, 2)))