__getitem__에서 슬라이싱 구현


112

벡터 표현을 만드는 클래스에 대한 슬라이스 기능을 구현하려고합니다.

나는 지금 까지이 코드를 가지고 있는데, 슬라이스를 제대로 구현할 것이라고 생각하지만 v[4]v가 벡터 인 곳 과 같은 호출을 할 때마다 파이썬은 충분한 매개 변수가 없다는 오류를 반환합니다. 그래서 나는 getitem일반 인덱스와 슬라이싱을 모두 처리하기 위해 클래스에서 특수 메서드 를 정의하는 방법을 알아 내려고 노력하고 있습니다.

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]

답변:


118

__getitem__()메서드는 slice개체가 슬라이스 될 때 개체 를받습니다 . 간단하게 보면 start, stopstep의 회원 slice슬라이스 구성 요소를 얻기 위해 객체입니다.

>>> 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')

10
참고 : 목록 또는 튜플과 같은 내장 유형을 확장하려면 __getslice__python 2.X 버전을 구현해야합니다 . 참조 docs.python.org/2/reference/datamodel.html#object.__getslice__
gregorySalvan

@gregorySalvan : 해당 섹션 아래의 호환성 예제가 반복되지 않습니까?
Eric

3
@Eric : 아니요, 두 번째 콜론의 존재는 __get/set/delslice__. 그래도 꽤 미묘합니다.
user2357112 모니카 지원

@ user2357112 :와, 두 번째 콜론을 완전히 놓쳤습니다-감사합니다!
Eric

파이썬 2에서 새로운 스타일의 클래스를 생성의 @alancalvitti IIRC,
wjandrea

64

"합성"목록 (데이터가 메모리에 생성하려는 것보다 큰 목록)이 있으며 내 __getitem__모습은 다음과 같습니다.

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

슬라이스는 동일한 유형을 반환하지 않습니다. 이는 아니오입니다.하지만 저에게는 효과적입니다.


1
key> = len (self) if key <0 or key> = len (self)이면 안 되나요? 키 <-len (self)가 전달되면 어떻게됩니까?
estan

20

일반 인덱스와 슬라이싱을 모두 처리하기 위해 getitem 클래스를 정의하는 방법은 무엇입니까?

슬라이스가 자동으로 첨자 표기법에 콜론을 사용할 때 작성되는 객체 - 그리고 에게 전달되는 것입니다 __getitem__. isinstance슬라이스 객체가 있는지 확인하는 데 사용 합니다.

from __future__ import print_function

class Sliceable(object):
    def __getitem__(self, subscript):
        if isinstance(subscript, slice):
            # do your handling for a slice object:
            print(subscript.start, subscript.stop, subscript.step)
        else:
            # Do your handling for a plain index
            print(subscript)

범위 객체를 사용하고 있었지만 슬라이스가 새 범위 객체 대신 목록을 반환하기를 원한다고 가정 해 보겠습니다.

>>> range(1,100, 4)[::-1]
range(97, -3, -4)

내부 제한으로 인해 범위를 하위 클래스로 지정할 수 없지만 위임 할 수 있습니다.

class Range:
    """like builtin range, but when sliced gives a list"""
    __slots__ = "_range"
    def __init__(self, *args):
        self._range = range(*args) # takes no keyword arguments.
    def __getattr__(self, name):
        return getattr(self._range, name)
    def __getitem__(self, subscript):
        result = self._range.__getitem__(subscript)
        if isinstance(subscript, slice):
            return list(result)
        else:
            return result

r = Range(100)

완벽하게 교체 가능한 Range 개체는 없지만 상당히 가깝습니다.

>>> r[1:3]
[1, 2]
>>> r[1]
1
>>> 2 in r
True
>>> r.count(3)
1

슬라이스 표기법을 더 잘 이해하기 위해 다음은 Sliceable의 사용 예입니다.

>>> 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는 다음 사항에 유의하십시오.

Python 2에는 일부 내장 유형을 서브 클래 싱 할 때 재정의해야하는 더 이상 사용되지 않는 메서드가 있습니다.

로부터 데이터 모델 문서 :

object.__getslice__(self, i, j)

버전 2.0부터 폐지 : 슬라이스 객체를 __getitem__()메소드 에 대한 매개 변수로 지원합니다 . (그러나 CPython의 기본 제공 형식은 현재 여전히를 구현 __getslice__()합니다. 따라서 슬라이싱을 구현할 때 파생 클래스에서이를 재정의해야합니다.)

이것은 Python 3에서 사라졌습니다.


7

상황이 좋아을 위해, 아론의 답변을 확장하려면 numpy, 당신이 있는지 확인하여 다차원 슬라이스를 할 수있는 givenA는 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]

```

산출:

('plain', 1)
('slice', None, None, None)
('multidim', (slice(1, None, None), slice(None, None, 2)))

미성년자의 후속으로, 여기에 예입니다 로, MATLAB 인덱싱 및 (현재 MATLAB R2016b에서 지원되지 않습니다) NumPy와 인덱싱 사이에 매핑이 사용의 예를 사용 그것의.
Eric Cousineau 2017 년

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.