2016-11-23 29 views
2

我想包括一些元數據到一個python切片對象,並添加變量來指示切片中每個元素的索引。元數據用於標記切片正在檢索的每個元素。我知道還有其他可以使用的標籤數據結構,但在我的項目中,slice被預定義爲numpy數組的下標,並在各個地方重新使用。所以,對我來說,找到一種合併這種方式是有道理的。是否可以模仿python切片對象或子類?

我在考慮分類slice,但顯然它不能是subclassed,這在鏈接問題的答案中已清楚解釋。從那以後有什麼變化嗎?

我希望做的是創建一個類,看起來像:

class Subscript: 
    def __init__(self, start, stop, step=None, labels=None): 
     self.labels = labels 
     self.slc = slice(start, stop, step) 

     for i, l in zip(range(start, stop, step), labels): 
      setattr(self, l, i) 

,並能夠使用這樣的:

sub = Subscript(0, 5, labels=['s0', 's1', 's2', 's3', 's4']) 

list(range(10))[sub] # [0, 1, 2, 3, 4] 

range(10)[sub.s0] # 0 

是有辦法做到這一點沒有不得不添加一個__call__方法來返回片?不知何故,我懷疑這是因爲在sub__getitem__的數組或列表不知道如何處理。我知道我可能只是將這些信息猴子補丁到slice,但我想知道這種類型的東西是否可以在課堂上完成。

目前,我分別限定所述切片和切片元素,如:

sub = slice(0, 5) 

s0, s1, s2, s3, s4 = range(5) 

但是,這種方法使得它更難多維數組的輸出處理爲一個字典,其中鍵是下標元素的組合的情況下大於1的sub並且值是1d陣列。

+1

請不要使用'exec'動態設置屬性,'setattr'更適合這個。另外,你的'__init__'沒有'self'。 – vaultah

+0

謝謝!忘記那個 – pbreach

回答

1

不可以,slice對象仍然不能被分類。我說默認爲PySlice_Type定義這個基於Python的on the flags3.7)分支:

Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 

爲了讓一個對象作爲一個基類的適當Py_TPFLAGS_BASETYPEor編輯在那裏,他們與類型定義允許。以lists作爲一個例子,它們的標誌定義爲:

Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | 
    Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LIST_SUBCLASS,   /* tp_flags */ 

忽略其餘部分,Py_TPFLAGS_BASETYPE是在那裏允許它充當基類|「編

由於我無法在文檔中的某處找到這個事實來判斷,我會說這是一個實現細節,其原因我目前還沒有意識到。我相信你的唯一方法可能規避它是通過降到C並讓你的課程在那裏。

+0

感謝您的。看起來這比我想象的更復雜。即使是猴子補丁「切片」也不會因爲這個原因而變得可行。我只是得到一個'AttributeError'。 – pbreach

+1

Yup @pbreach如果我沒有記錯的話,'list .__ getitem__'(和其他容器應該有相似的行爲)明確地檢查一個'slice'類型作爲參數傳遞給它或'int'值(至少,提供'__index__'方法返回一個適當的'int')。你可能做的最好的事情實際上是創建一個新的'list'子類型,允許自定義對象的行爲像'切片'(通過組合可能?)。 –

+0

我最終基本上按照你的建議去做,除了通過繼承'numpy.ndarray'而不是'list'並在這裏發佈。適合我! – pbreach

1

我最終什麼事做的是子類numpy.ndarray因爲我只是想切片傳遞到這種類型的對象(可以做的名單相同),然後重新實現__getitem__這樣,如果Subscript對象被傳入,則切片將在傳遞到父方法之前首先被提取。

的樣子:

import numpy as np 

class SubArray(np.ndarray): 
    def __new__(cls, input_array, subs=None): 
     obj = np.asarray(input_array).view(cls) 
     obj.subs = subs 
     return obj 

    def __getitem__(self, *args): 
     args = tuple([a.slc if isinstance(a, SubRange) else a for a in args]) 
     return super().__getitem__(*args) 

    def __array_finalize__(self, obj): 
     if obj is None: 
      return 
     self.subs = getattr(obj, 'subs', None) 


class Subscript: 
    def __init__(self, labels, bounds=None): 
     name, elements = labels 

     if bounds: 
      start, stop = bounds 
     else: 
      start, stop = 0, len(elements) 

     self.size = stop - start 
     self.slc = slice(start, stop) 
     self.labels = labels 
     self.name = name 
     self.elements = elements 

     for l, i in zip(labels, range(start, stop)): 
      setattr(self, l, i) 

而且可以使用這樣的:

sub = Subscript(('sub', ['s0', 's1', 's2', 's3', 's4'])) 

SubArray(np.arange(10), subs=sub)[sub] # SubArray([0, 1, 2, 3, 4]) 

SubArray(np.arange(10), subs=sub)[sub.s0] # 0 

這是更接近,我是避免方法(即使用類似xarray),但結果是仍然基本上是一個numpy陣列,併爲我工作。

相關問題