2017-12-20 5 views
1

私はよく開発されたPythonクラス(Foo1Dと呼ぶ)を使用していますが、これは素晴らしいメソッドを備えていますが、1Dデータに対してのみ機能します。レポをフォークし、2Dデータを処理するすべてのメソッドを変更するのは非常に時間がかかります。クラスのリストを反復するPythonラッパー

だから、私は、無相関2D入力を受け付ける「ベクトル化」ラッパーFoo2Dを作るのが好きFoo1Dオブジェクトの集合に変換し、メソッドが呼び出され、コレクションを反復処理し、結果の配列を返すと思います。

は、ここで私が試したものです:

class Foo1D(object):  
    def __init__(self, data1D): 
     self.offset = 20 
     self.data = data1D+self.offset 

    def multiply(self, x): 
     return self.data*x 

    def add(self, a): 
     return self.data+a 

class Foo2D(object): 
    def __init__(self, data2D): 
     dummy = Foo1D(data2D[0]) 
     self.__class__ = type(dummy.__class__.__name__, (self.__class__, dummy.__class__), {}) 
     self.__dict__ = dummy.__dict__ 
     del dummy 

     self.data2D = [Foo1D(data1D) for data1D in data2D] 

    def __getattr__(self, item, *args, **kwargs): 
     result = [getattr(data1D, item)(*args, **kwargs) for data1D in self.data2D] 

     return np.array(result) 

これが正しい属性でFoo1DFoo2Dオブジェクトを作成しますが、期待通りにFoo2D方法は動作しません。例:私はA.multiply(2)を実行すると、期待どおり

a1D = np.arange(10) 
a2D = a1D.reshape(2,5) 
A = Foo1D(a1D) 
B = Foo2D(a2D) 

は、だから私はarray([40, 42, 44, 46, 48, 50, 52, 54, 56, 58])を取得します。

しかし、私がB.multiply(2)を実行すると、私はarray([[40, 42, 44, 46, 48],[50, 52, 54, 56, 58]])を得ると期待してarray([40, 42, 44, 46, 48])を得る。これは、B.dataa2Dの最初の要素にすぎない理由がわかりません。

もし私がnp.array([getattr(i, 'multiply')(2) for i in B.data2D])を実行すれば、私は期待した答えが得られますarray([[40, 42, 44, 46, 48],[50, 52, 54, 56, 58]])

これはなぜ起こっているのですか?ありがとう!

答えて

1

はあなたのコードが動作しない、いくつかの理由があります:

  1. はあなたがいない__getattr____getattribute__を使用します。実際にはFoo2D.__getattr__は呼び出されません(そこにprintステートメントを入れてみてください)。
  2. 固定小数点数1の場合、__getattribute__RuntimeError: maximum recursion depth exceededとなります。self.data2Dself.__getattribute__('data2D')に相当するためです。
  3. Foo2D.multiplyself.__class__ = type(dummy.__class__.__name__, (self.__class__, dummy.__class__), {})で設定されていると思いますので、Foo2D.data2D[0].multiplyを取得するだけです。私はこのラインに他の意図しない結果があると賭けても構わないと思う。
  4. selfと属性名のみがFoo2D.__getattribute__に渡されます。 Foo2D.__getattr__が関数を返す場合、この関数は他の引数(例えば*args, **kwargs)を処理します。

以下、私は希望の効果をもたらすと信じているFoo2Dのバージョンを実装しました。 Foo2D.__getattribute__object.__getattribute__を使用しようとし、AttributeErrorがスローされた場合(つまりその属性が設定されていない場合)にのみ特別な処理を行います。 Foo1Dの要求された属性が呼び出し可能(すなわち、関数)である場合、Foo2D._vec_attrが要素ごとの評価を行うために使用されます。さもなければ、それは単に属性のベクトルを与えます。Python2のために

:のpython3のために

class Foo2D(object): 
    def __init__(self, data2D): 
     self.data2D = [Foo1D(data1D) for data1D in data2D] 

    def __getattribute__(self, attr): 
     try: 
      return super(Foo2D, self).__getattribute__(attr) 
     except AttributeError: 
      if callable(getattr(self.data2D[0], attr)): 
       return lambda *args, **kwargs: self._vec_attr(attr, *args, **kwargs) 
      else: 
       return np.array([getattr(data1D, attr) for data1D in self.data2D]) 

    def _vec_attr(self, attr, *args, **kwargs): 
     return np.array([getattr(data1D, attr)(*args, **kwargs) for data1D in self.data2D]) 

class Foo2D(object): 
    def __init__(self, data2D): 
     self.data2D = [Foo1D(data1D) for data1D in data2D] 

    def __getattribute__(self, attr): 
     try: 
      return super().__getattribute__(attr) 
     except AttributeError: 
      if callable(getattr(self.data2D[0], attr)): 
       return lambda *args, **kwargs: self._vec_attr(attr, *args, **kwargs) 
      else: 
       return np.array([getattr(data1D, attr) for data1D in self.data2D]) 

    def _vec_attr(self, attr, *args, **kwargs): 
     return np.array([getattr(data1D, attr)(*args, **kwargs) for data1D in self.data2D]) 

差がsuperへの呼び出しです。

+0

素晴らしい!どうもありがとうございました。 –

+0

特定のメソッドを呼び出すときに 'TypeError:super(type、obj):objがインスタンスまたはサブタイプである必要があります。 'という行7を' return super().__ getattribute __(attr) 'に変更して動作させます今の魅力のように。再度、感謝します! –

+1

ああ、はい。これはPython 2対3の問題です。私のコードはPython 2用に書かれており、Python 3を実行しています。 – shockburner