Python: La mise en œuvre dans le découpage __getitem__
-
05-10-2019 - |
Question
Je suis en train de mettre en œuvre la fonctionnalité de tranche pour une classe que je fais qui crée une représentation vectorielle.
Je le code à ce jour, qui, je crois bien mettre en œuvre la tranche, mais chaque fois que je fais un appel comme v[4]
où v est un python vecteur renvoie une erreur de ne pas avoir assez de paramètres. J'essaie donc de comprendre comment définir la méthode getitem
spéciale dans ma classe pour gérer les deux indices simples et trancher.
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 solution
La méthode __getitem__()
recevra un objet slice
lorsque l'objet est coupé en tranches. Il suffit de regarder le start
, stop
, et les membres de step
de l'objet slice
afin d'obtenir les composants pour 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')
Autres conseils
J'ai une liste « synthétique » (celui où les données est plus grand que vous voulez créer dans la mémoire) et mes regards __getitem__
comme ceci:
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 retourne pas le même type, ce qui est un non-non, mais ça marche pour moi.
Comment définir la classe getitem pour gérer les index simples et découpage en tranches?
objets Slice créée automatiquement lorsque vous utilisez deux points dans la notation de l'indice - et que est ce qui est passé à __getitem__
. Utilisez isinstance
pour vérifier si vous avez un objet de 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
Python 2, il faut savoir:
En Python 2, il y a une méthode désapprouvée que vous devrez peut-être remplacer lorsque certains types de sous-classement BUILTIN.
De la datamodel documentation :
object.__getslice__(self, i, j)
Obsolète depuis la version 2.0: objets tranche de support en tant que paramètres à la méthode
__getitem__()
. (Cependant, les types intégrés dans CPython mettent actuellement en œuvre encore__getslice__()
. Par conséquent, vous devez le remplacer dans les classes dérivées lors de la mise en œuvre découpage en tranches.)
est parti en Python 3.
La bonne façon de le faire est d'avoir __getitem__
prendre un paramètre, qui peut être un nombre ou un objet de tranche.
Voir:
http://docs.python.org/library/functions.html#slice
http://docs.python.org/reference/datamodel.html#object.__getitem__
Pour prolonger la réponse d'Aaron, pour des choses comme numpy
, vous pouvez le faire trancher multi-dimensionnelle 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)))