2016-11-23 11 views
2

私はPythonスライスオブジェクトにいくつかのメタデータを追加し、スライス内の各要素のインデックスを示す変数を追加したいと思います。メタデータは、スライスが取得している各要素にラベルを付けるために使用されます。私は使用できる他のラベル付けされたデータ構造があることを知っていますが、私のプロジェクトでは、スライスは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

ありがとう!その1つを忘れた – pbreach

答えて

1

いいえ、sliceオブジェクトはまだサブクラス化できません。私は、デフォルトのPython(3.7)ブランチでPySlice_Typeのために定義され、このベースon the flagsを言っている:

Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 

オブジェクトは基本クラスとして適切なPy_TPFLAGS_BASETYPEを作用させるために、彼らはタイプであるとして、そこにor編だろう定義することができます。例として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

私が正しく覚えていれば、 'list .__ getitem__'(そして他のコンテナも同様に動作するはずです)は' slice'型を渡す引数として明示的にチェックします。 '__index__'メソッドが適切な' int'を返します)。可能な限り最高のことは、実際に 'slice'sのように動作するカスタムオブジェクトを可能にする新しい' list'サブタイプを作成することです。 –

+0

私は 'list'の代わりに' numpy.ndarray'をサブクラス化してここに掲示する以外に、あなたが提案したものを基本的にやってしまいました。私のために働く! – pbreach

1

私は何をやってしまったことは、私は唯一のオブジェクトのこの型にスライスを渡そうとしたため、(リストのために同じことを行うことができます)numpy.ndarrayをサブクラス化し、そのようSubscriptオブジェクトは、その後に渡された場合__getitem__を再実装されますスライスは最初に親メソッドに渡される前に抽出されます。

次のようになります。

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のようなものを使用してIE)回避されたアプローチに非常に近いですが、結果はまだ基本的には、私のためにnumpyの配列と働いています。

関連する問題