2016-07-06 9 views
6

で__rmul__オペレータ、私はクラスを作成し、私はこの新しいクラスと実際の行列間の動作を必要とするので、私はこのアレイおよびプロジェクトでPythonのnumpyの

class foo(object): 

    aarg = 0 

    def __init__(self): 
     self.aarg = 1 


    def __rmul__(self,A): 
     print(A) 
     return 0 

    def __mul__(self,A): 
     print(A) 
     return 0 

が、ときのように__rmul__機能を過負荷に私は

0 
0 
0 
1 
0 
2 

:私はそれを呼ばれ、結果は私が

A = [[i*j for i in np.arange(2) ] for j in np.arange(3)] 
A = np.array(A) 
R = foo() 
C = A * R 

出力を期待したものではなかったです関数が各要素に対して1回、6回呼び出されるようです。

代わりに、__mul__機能が大幅に機能

C = R * A 

出力:

[[0 0] 
[0 1] 
[0 2]] 

Aが配列ではなく、リストのリストだけならば、両方の罰金

A = [[i*j for i in np.arange(2) ] for j in np.arange(3)] 
R = foo() 
C = A * R 
C = R * A 
を働きます

出力

[[0, 0], [0, 1], [0, 2]] 
[[0, 0], [0, 1], [0, 2]] 

実際に私の__rmul__関数が配列に対しても機能したいと思います(私の元の乗算関数は可換ではありません)。どうすれば解決できますか?

+0

「A」の種類を確認するにはどう思いますか? –

答えて

4

動作が必要です。

まず、x*yのような操作が実際にどのように実行されているかを理解する必要があります。 Pythonインタプリタは、最初にを試します。x.__mul__(y)を試してください。 この呼び出しがNotImplementedを返す場合、を返します。y.__rmul__(x)を計算しようとします。 の場合yがタイプxの適切なサブクラスである場合、この場合、インタープリタは最初にy.__rmul__(x)とし、次にx.__mul__(y)とみなします。

ここで、numpyは、引数がスカラーまたは配列であると考えるかどうかによって引数を異なる方法で扱います。

*は、要素ごとの乗算を行いますが、スカラー倍計算では配列のすべてのエントリに指定されたスカラーを乗算します。

foo()はnumpyでスカラーとみなされ、numpyは配列のすべての要素にfooを乗じます。また、numpyのはタイプfooについて知らないので、オブジェクトが返されるので、それは、dtype=objectとの配列を返します:

array([[0, 0], 
     [0, 0], 
     [0, 0]], dtype=object) 

注:numpyの配列がないリターンNotImplementedあなたが計算しようとしませんしたがって、インタープリタは、numpyの配列__mul__メソッドを呼び出します。このメソッドは、前述のようにスカラー乗算を実行します。この時点でnumpyは配列の各エントリに "スカラー" foo()を掛けようとします。__mul__foo引数で呼び出されたときに、配列内の数値がNotImplementedを返すため、ここでは__rmul__メソッドが呼び出されます。

引数の順序を最初の乗算に変更すると、明らかに__mul__メソッドが呼び出され、何の問題もありません。

だから、あなたの質問に答えるために、これを処理する一つの方法は、第二の規則が適用されるように、ndarrayからfoo継承を持つことです。しかし、そのsubclassing ndarray isn't straightforward

class foo(np.ndarray): 
    def __new__(cls): 
     # you must implement __new__ 
    # code as before 

警告。 さらに、あなたのクラスがndarrayであるので、他の副作用があるかもしれません。

+0

numpyは 'foo'インスタンスがスカラーであると判断するロジックは何ですか? – wim

+0

@wim配列でない場合はスカラーです。それと同じくらい簡単です。 – Bakuriu

1

私は基本的な問題を爆破と同じくらい正確に説明することはできませんでしたが、別の解決方法があるかもしれません。

__array_priority__を定義することにより、numpyに評価方法の使用を強制することができます。説明したようにnumpyの文書でhere。あなたのクラスで__numpy_ufunc__関数を定義することができます

MAGIC_NUMBER = 15.0 
# for the necessary lowest values of MAGIC_NUMBER look into the numpy docs 
class foo(object): 
    __array_priority__ = MAGIC_NUMBER 
    aarg = 0 

    def __init__(self): 
     self.aarg = 1 


    def __rmul__(self,A): 
     print(A) 
     return 0 

    def __mul__(self,A): 
     print(A) 
     return 0 
0

は、あなたのケースでは、あなたはあなたにクラス定義を変更しなければなりませんでした。np.ndarrayをサブクラス化せずにでも動作します。あなたはここにドキュメントを見つけることができます:ここで

https://docs.scipy.org/doc/numpy/neps/ufunc-overrides.htmlがあなたのケースをもとに例です:

class foo(object): 

    aarg = 0 

    def __init__(self): 
     self.aarg = 1 

    def __numpy_ufunc__(self, *args): 
     pass 

    def __rmul__(self,A): 
     print(A) 
     return 0 

    def __mul__(self,A): 
     print(A) 
     return 0 

そして、我々はそれをしようとした場合、

A = [[i*j for i in np.arange(2) ] for j in np.arange(3)] 
A = np.array(A) 
R = foo() 
C = A * R 

出力:

[[0 0] 
[0 1] 
[0 2]] 

それは動作します!

関連する問題