[python] __getitem__에서 슬라이싱 구현

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

나는 지금 까지이 코드를 가지고 있는데, 슬라이스를 제대로 구현할 것이라고 생각하지만 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]



답변

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


답변

“합성”목록 (데이터가 메모리에 생성하려는 것보다 큰 목록)이 있으며 내 __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."

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


답변

일반 인덱스와 슬라이싱을 모두 처리하기 위해 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에서 사라졌습니다.


답변

상황이 좋아을 위해, 아론의 답변을 확장하려면 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)))


답변

이를 수행하는 올바른 방법은 __getitem__ 은 하나의 매개 변수 (숫자 또는 슬라이스 객체 일 수 있음)를 갖는 것입니다.

보다:

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

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


답변