Python: Implementazione di affettare in __getitem__
-
05-10-2019 - |
Domanda
Sto cercando di implementare la funzionalità fetta per una classe che sto facendo che crea una rappresentazione vettoriale.
Ho questo codice finora, che credo applicare correttamente la fetta, ma ogni volta che faccio una chiamata come v[4]
dove v è un vettore di pitone restituisce un errore di non avere abbastanza parametri. Così sto cercando di capire come definire il metodo speciale getitem
nella mia classe per gestire sia gli indici di pianura e affettare.
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]
Soluzione
Il metodo __getitem__()
riceverà un oggetto slice
quando l'oggetto viene affettato. Basta guardare il start
, stop
, e membri step
dell'oggetto slice
al fine di ottenere i componenti della porzione.
>>> 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')
Altri suggerimenti
Ho una lista "sintetico" (quella in cui il dato è più grande di quanto si vorrebbe creare in memoria) e il mio aspetto __getitem__
come questo:
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 fetta non restituisce lo stesso tipo, che è un no-no, ma funziona per me.
Come definire la classe getitem per gestire sia gli indici semplici e affettare?
Slice oggetti viene creato automaticamente quando si utilizza un colon nella notazione pedice - e che è ciò che è passato a __getitem__
. Utilizzare isinstance
per verificare se si dispone di un oggetto porzione:
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)
Esempio di utilizzo:
>>> 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, essere consapevoli:
In Python 2, c'è un metodo deprecato che potrebbe essere necessario eseguire l'override quando sottoclasse alcuni tipi built-in.
object.__getslice__(self, i, j)
Sconsigliata a partire da versione 2.0: fetta supporta gli oggetti come parametri al metodo
__getitem__()
. (Tuttavia, tipi built-in in CPython attualmente ancora implementare__getslice__()
. Pertanto, è necessario eseguire l'override in classi derivate in sede di attuazione affettare.)
Questo è andato in Python 3.
Il modo corretto per farlo è avere __getitem__
prendere un parametro, che può essere un numero o un oggetto porzione.
Si veda:
http://docs.python.org/library/functions.html#slice
http://docs.python.org/reference/datamodel.html#object.__getitem__
Per estendere la risposta di Aaron, per le cose come numpy
, si può fare per affettare multi-dimensionale controllando per vedere se given
è 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]
`` `
Output:
('plain', 1)
('slice', None, None, None)
('multidim', (slice(1, None, None), slice(None, None, 2)))