1

私は「魔法のメソッド」の構文や、Pythonで呼び出されるものなどが本当に好きです。

class foo:
    def __add__(self,other): #It can be called like c = a + b
        pass

呼び出し

c = a + b

その後、に翻訳されます

a.__add__(b)

「非魔法」関数のそのような動作を模倣することは可能ですか?数値計算では、クロネッカー積が必要であり、次のような「クロネッカー」関数が必要です。

kron(a,b) 

実は

a.kron(b)?

ユースケースは次のとおりです。たとえば、行列とベクトルの2つの類似したクラスがあり、どちらもクロネッカー積を持っています。呼びたい

a = matrix()
b = matrix()
c = kron(a,b)

a = vector()
b = vector()
c = kron(a,b)

行列クラスとベクトルクラスは1つの.pyファイルで定義されるため、共通の名前空間を共有します。では、上記のような関数を実装するための最良の(Pythonic?)方法は何ですか?可能な解決策:

1)1つのkron()関数を持ち、型チェックを行います

2)異なる名前空間を持つ

3)?

4

4 に答える 4

7

Pythonのデフォルトの演算子メソッド(__add__およびそのようなもの)はハードワイヤードです。演算子の実装がそれらを探すので、pythonはそれらを探します。

kronただし、同じことを行う関数を定義することを妨げるものは何もありません。渡されたオブジェクトを探します__kron____rkron__

def kron(a, b):
    if hasattr(a, '__kron__'):
        return a.__kron__(b)
    if hasattr(b, '__rkron__'):
        return b.__rkron__(a)
    # Default kron implementation here
    return complex_operation_on_a_and_b(a, b)
于 2012-07-09T08:01:13.737 に答える
4

あなたが説明しているのは、複数のディスパッチまたはマルチメソッドです。マジックメソッドはそれらを実装する1つの方法ですが、実際には、タイプ固有の実装を登録できるオブジェクトを持っている方が一般的です。

たとえば、http://pypi.python.org/pypi/multimethod/を使用すると、次のように記述できます。

@multimethod(matrix, matrix)
def kron(lhs, rhs):
    pass

@multimethod(vector, vector)
def kron(lhs, rhs):
    pass

マルチメソッドデコレータを自分で作成するのは非常に簡単です。BDFLは、記事の典型的な実装について説明しています。multimethodデコレータは、型シグネチャとメソッドをレジストリ内のメソッド名に関連付け、そのメソッドを、型ルックアップを実行して最適なものを見つける生成されたメソッドに置き換えるという考え方です。

于 2012-07-09T08:21:22.347 に答える
3

技術的に言えば、「標準」演算子(および演算子のような-thinklen()など)の動作に似たものを実装することは難しくありません。

def kron(a, b):
    if hasattr(a, '__kron__'):
        return a.__kron__(b)
    elif hasattr(b, '__kron__'):
        return b.__kron__(a)
    else:
        raise TypeError("your error message here")

ここで、関連する型にメソッドを追加する__kron__(self, other)必要があります(これらの型を制御できるか、スロットなど、クラスステートメントの本体の外にメソッドを追加できないようなものを使用しないと仮定します)。

__magic__これは言語自体のために予約されているはずなので、上記のスニペットのような命名スキームは使用しません。

type別の解決策は、 :マッピングを維持し、specifici functionマッピングを検索する「ジェネリック」kron関数を使用することです。

# kron.py
from somewhere import Matrix, Vector

def matrix_kron(a, b):
    # code here

def vector_kron(a, b):
    # code here

KRON_IMPLEMENTATIONS = dict(
    Matrix=matrix_kron,
    Vector=vector_kron,
    )

def kron(a, b):
    for typ in (type(a), type(b)):
        implementation = KRON_IMPLEMENTATION.get(typ, None)
        if implementation:
            return implementation(a, b)
    else:
        raise TypeError("your message here")

このソリューションは継承ではうまく機能しませんが、「驚くことは少ない」です。モンキーパッチや__magic__名前などは必要ありません。

于 2012-07-09T07:59:09.743 に答える
0

実際の計算を委任する単一の関数を持つことは、それを行うための良い方法だと思います。クロネッカー積が2つの類似したクラスでのみ機能する場合は、関数で型チェックを行うこともできます。

def kron(a, b):
    if type(a) != type(b):
        raise TypeError('expected two instances of the same class, got %s and %s'%(type(a), type(b)))
    return a._kron_(b)

_kron_次に、クラスでメソッドを定義する必要があります。これは基本的な例にすぎません。クラスに_kron_メソッドがない場合をより適切に処理したり、サブクラスを処理したりするために、これを改善することをお勧めします。

標準ライブラリの二項演算には通常、逆二項(__add____radd__)がありますが、演算子は同じ型のオブジェクトに対してのみ機能するため、ここでは役に立ちません。

于 2012-07-09T08:00:11.270 に答える