Python: Implementieren von Slicing in __getitem__
-
05-10-2019 - |
Frage
Ich versuche, in Scheiben schneiden Funktionalität für eine Klasse zu implementieren ich, damit ich bin das schafft eine Vektordarstellung.
Ich habe diesen Code so weit, das ich glaube, richtig die Scheibe implementieren, aber wenn ich einen Anruf wie v[4]
tun, wo v ein Vektor Python einen Fehler zurückgibt über nicht genügend Parameter aufweisen. Also ich versuche, herauszufinden, wie die getitem
spezielle Methode in meiner Klasse definieren beide Ebene Indizes und Slicing zu behandeln.
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]
Lösung
Die __getitem__()
Methode wird ein slice
Objekt erhalten, wenn das Objekt in Scheiben geschnitten wird. Einfach auf der start
, stop
und step
Mitglieder des slice
Objekts, um die Komponenten für die Scheibe zu erhalten.
>>> 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')
Andere Tipps
Ich habe eine „synthetische“ Liste (eine, wo die Daten, die größer ist, als Sie im Speicher erstellen möchte) und meine __getitem__
sieht wie folgt aus:
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."
Die Scheibe nicht den gleichen Typ zurückgeben, das ist ein no-no, aber es funktioniert für mich.
Wie die getitem Klasse zu definieren, beide Indizes Ebene und schneiden zu behandeln?
Slice-Objekte wird automatisch erstellt, wenn Sie einen Doppelpunkt in der Index-Notation - und , die ist, was zu __getitem__
geben wird. Verwenden isinstance
zu überprüfen, ob Sie ein Slice-Objekt haben:
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)
Beispiel Nutzung:
>>> 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, beachten Sie:
In Python 2 gibt es eine veraltete Methode, dass Sie außer Kraft setzen müssen, wenn einige eingebauten Typen Subklassen.
Von der Datenmodell Dokumentation :
object.__getslice__(self, i, j)
Veraltet seit Version 2.0: Support Segmentobjekte als Parameter an die
__getitem__()
Methode. (Allerdings eingebauten Typen in CPython derzeit noch__getslice__()
implementieren. Deshalb müssen Sie es in abgeleiteten Klassen außer Kraft setzen, wenn Slicing implementieren.)
Dies ist in Python 3 weg.
Der richtige Weg, dies zu tun ist, __getitem__
nimmt einen Parameter zu haben, die entweder eine Zahl sein können, oder ein Segmentobjekt.
Siehe auch:
http://docs.python.org/library/functions.html#slice
http://docs.python.org/reference/datamodel.html#object.__getitem__
Um Aaron Antwort, für Dinge wie numpy
zu erweitern, können Sie mehrdimensionale Slicing tun, indem Sie überprüfen, ob given
ein tuple
ist:
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]
`` `
Ausgabe:
('plain', 1)
('slice', None, None, None)
('multidim', (slice(1, None, None), slice(None, None, 2)))