2010-05-29 38 views
73

中實現切片我正在試圖爲一個類實現切片功能,我創建了這個切片來創建一個向量表示。Python:在__getitem__

我有這個代碼到目前爲止,我相信會正確實現切片,但每當我做一個像v[4]這樣的調用,其中v是一個向量python返回一個關於沒有足夠的參數的錯誤。所以我想弄清楚如何在我的類中定義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] 

回答

79

當對象切片的__getitem__()方法將收到一個slice對象。只需查看slice對象的startstopstep成員即可獲取切片的組件。

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

注:擴展內建類型,如列表或元組必須實現'Python的2.X版本__getslice__'。請參閱https://docs.python.org/2/reference/datamodel.html#object.__getslice__ – gregorySalvan 2014-08-28 05:17:19

+0

@gregorySalvan:該部分下面的那個兼容性示例是否只是遞歸? – Eric 2016-08-19 19:10:31

+1

@Eric:不,因爲第二個冒號的存在會繞過'__get/set/delslice__'。雖然這很微妙。 – user2357112 2017-05-25 01:41:44

54

我有一個「合成」列表(即一個數據大於你想在內存中創建)和我__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." 

切片不返回相同的類型,這是一個no-不,但它適用於我。

+1

如果key> = len(self)be if key= len(self)?如果一個關鍵<-len(self)被傳遞了會怎麼樣? – estan 2016-06-01 17:50:34

+0

@estan:我認爲它應該涵蓋你提到的情況。 – 2016-06-02 15:58:38

+0

@estan你說得對。現在編輯它。 – 2016-06-03 03:14:50

6

如何定義getitem類來處理普通索引和切片?和就是傳遞給__getitem__ - 當您使用的下標符號冒號

切片對象被自動創建。使用isinstance檢查,如果你有一個切片對象:

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) 

用法示例:

>>> 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 
3

爲了延長阿龍的回答,對於像numpy,你可以通過檢查,看是否做多維度切片giventuple

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))) 
+0

作爲一個小的後續,這裏[是一個例子](https://github.com/EricCousineau-TRI/repro/blob/62151af/bindings/mlmodule/NumPyProxy.m#L83)使用此映射MATLAB索引和NumPy索引(目前在MATLAB R2016b中不支持),[示例用法](https://github.com/EricCousineau-TRI/repro/blob/62151af/bindings/mlmodule/test/example_py_slice.m# L43)。 – 2017-05-30 05:02:37

相關問題