Python: Implementing slicing in getitem

Próbuję zaimplementować funkcjonalność slice dla tworzonej przeze mnie klasy, która tworzy reprezentację wektorową.

Mam ten kod do tej pory, który wierzę, że poprawnie zaimplementuje kawałek, ale za każdym razem, gdy wykonuję wywołanie jak v[4] Gdzie V jest wektorem python zwraca błąd o niewystarczającej ilości parametrów. Więc staram się dowiedzieć, jak zdefiniować getitem specjalną metodę w mojej klasie, aby obsługiwać zarówno zwykłe indeksy, jak i krojenie.

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]
Author: Aaron Hall, 2010-05-30

5 answers

Metoda __getitem__() otrzyma obiekt slice, gdy obiekt zostanie przecięty. Wystarczy spojrzeć na start, stop, i step członków obiektu slice w celu uzyskania komponentów dla plasterka.

>>> 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')
 92
Author: Ignacio Vazquez-Abrams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-29 22:56:39

Mam "syntetyczną" listę (taką, w której dane są większe niż chciałbyś utworzyć w pamięci) i moja __getitem__ wygląda tak:

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."

Plasterek nie zwraca tego samego typu, CO Nie-Nie, ale działa na mnie.

 56
Author: Walter Nissen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-03 03:15:33

Jak zdefiniować klasę getitem do obsługi zarówno zwykłych indeksów, jak i slicingu?

Obiekty Slice są tworzone automatycznie, gdy używasz dwukropka w notacji dolnej - i to jest tym, co jest przekazywane do __getitem__. Użyj isinstance, aby sprawdzić, czy masz obiekt slice:

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)

Przykładowe użycie:

>>> 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
 7
Author: Aaron Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-22 21:47:42

Poprawnym sposobem jest pobranie __getitem__ jednego parametru, który może być liczbą lub obiektem slice.

Zobacz:

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

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

 7
Author: carl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-21 01:07:04

Aby rozszerzyć odpowiedź Aarona, dla rzeczy takich jak numpy, możesz wykonać wielowymiarowe krojenie, sprawdzając, czy given jest 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]

```

Wyjście:

('plain', 1)
('slice', None, None, None)
('multidim', (slice(1, None, None), slice(None, None, 2)))
 4
Author: Eric Cousineau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-25 01:35:09