私はベクトル(つまり、数値のリスト)の数学演算を支援する単純なクラスを持っています。私のVector
は、Vector
orスカラー(float
またはint
)の他のインスタンスで乗算できます。
他のより強く型付けされた言語では、2つのvector
sを乗算するメソッドと、vector
とint
/float
を乗算する別のメソッドを作成します。私はPython=にまだまだ慣れていないので、これをどのように実装するかわかりません。それを行うには、オーバーライド__mul__()
を使用し、受信パラメータをテストするしかありません。 :
class Vector(object):
...
def __mul__(self, rhs):
if isinstance(rhs, Vector):
...
if isinstance(rhs, int) or isinstance(rhs, float):
...
そのようにしても、Vector
に次のようなスカラーを掛ける必要があります。
v = Vector([1,2,3])
result = v * 7
乗算のオペランドの順序を逆にしたい場合はどうなりますか?
result = 7 * v
Pythonでそれを行う正しい方法は何ですか?
___rmul__
_も実装する必要があります。 int.__mul__(7, v)
への最初の呼び出しが失敗すると、Pythonは次にtype(v).__rmul__(v, 7)
を試行します。
_def __rmul__(self, lhs):
return self * lhs # Effectively, turn 7 * v into v * 7
_
Rawingが指摘するように、この定義に対して___rmul__ = __mul__
_を単純に書くことができます。 ___rmul__
_は、非可換乗算を可能にするために存在し、オペランドを逆にして___mul__
_に単に延期するだけでは不十分です。
たとえば、Matrix
クラスを作成していて、ネストされたリストによる乗算をサポートしたい場合は、たとえば、
_m = Matrix(...) # Some 2 x 2 matrix
n = [[1, 2], [3,4]]
p = n * m
_
ここで、list
クラスはMatrix
インスタンスでリストを複数にする方法を知らないため、list.__mul__(n, m)
が失敗した場合、Python次にMatrix.__rmul__(m, n)
を試します。ただし、_n * m
_と_m * n
_は一般に2つの異なる結果であるため、Matrix.__rmul__(m, n) != Matrix.__mul__(m, n)
; ___rmul__
_は少し実行する必要があります正しい答えを生成するための余分な作業。
逆の操作のための特別な方法 があります:
__rmul__
_の逆の場合は___mul__
___radd__
_の場合は___add__
_、これらは、通常の演算で左側の演算子がNotImplemented
を返すときに呼び出されます(したがって、演算_2 + vector_instance
_はまず_(2).__add__(vector_instance)
_を試行しますが、これがNotImplemented
を返す場合はvector_instance.__radd__(2)
が呼び出されます)。
ただし、算術特殊メソッドでisinstance
チェックを使用しないと、コードの繰り返しが多くなります。
実際に___init__
_で特別なケースを作成し、スカラーからVector
への変換を実装できます。
_class Vector(object):
def __init__(self, x, y=None, z=None):
if y is None and z is None:
if isinstance(x, Vector):
self.x, self.y, self.z = x.x, x.y, x.z
else:
self.x, self.y, self.z = x, x, x
Elif y is None or z is None:
raise ValueError('Either x, y and z must be given or only x')
else:
self.x, self.y, self.z = x, y, z
def __mul__(self, other):
other = Vector(other)
return Vector(self.x*other.x, self.y*other.y, self.z*other.z)
__rmul__ = __mul__ # commutative operation
def __sub__(self, other):
other = Vector(other)
return Vector(self.x-other.x, self.y-other.y, self.z-other.z)
def __rsub__(self, other): # not commutative operation
other = Vector(other)
return other - self
def __repr__(self):
return 'Vector({self.x}, {self.y}, {self.z})'.format(self=self)
_
これは期待どおりに機能するはずです。
_>>> 2 - Vector(1, 2, 3)
Vector(1, 0, -1)
>>> Vector(1, 2, 3) - 2
Vector(-1, 0, 1)
>>> Vector(1, 2, 3) * 2
Vector(2, 4, 6)
>>> 2 * Vector(1, 2, 3)
Vector(2, 4, 6)
_
これは素早い汚いドラフトであったことに注意してください(いくつかのバグがある可能性があります)。私は、各算術演算で型を特別にケーシングすることなく、それをどのように解決できるかという「一般的なアイデア」を提示したかっただけです。