Rob*_*eph 16 python class operator-overloading operators
我有一个简单的类,可以帮助对向量进行数学运算(即数字列表).我Vector可以乘以其他实例Vector 或标量(float或int).
在其他更强类型的语言中,我将创建一个方法来将两个vectors和一个单独的方法相乘以乘以vector和int/ float.我仍然是Python的新手,我不确定如何实现它.我能想到的唯一方法是覆盖__mul__()并测试传入的参数:
class Vector(object):
...
def __mul__(self, rhs):
if isinstance(rhs, Vector):
...
if isinstance(rhs, int) or isinstance(rhs, float):
...
Run Code Online (Sandbox Code Playgroud)
即使我这样做,我也会被迫乘以这样Vector的标量:
v = Vector([1,2,3])
result = v * 7
Run Code Online (Sandbox Code Playgroud)
如果我想在乘法中颠倒操作数的顺序怎么办?
result = 7 * v
Run Code Online (Sandbox Code Playgroud)
在Python中这样做的正确方法是什么?
che*_*ner 18
你还需要实现__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
Run Code Online (Sandbox Code Playgroud)
正如Rawing指出的那样,你可以简单地__rmul__ = __mul__为这个定义写.__rmul__存在允许非交换乘法,其中简单地推迟__mul__操作数被逆转是不够的.
例如,如果您正在编写一个Matrix类并希望通过嵌套列表支持乘法,例如,
m = Matrix(...) # Some 2 x 2 matrix
n = [[1, 2], [3,4]]
p = n * m
Run Code Online (Sandbox Code Playgroud)
这里,list类不知道如何通过Matrix实例复制列表,所以当list.__mul__(n, m)失败时,Python会接下来尝试Matrix.__rmul__(m, n).然而,n * m与m * n在一般的两种不同的结果,所以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)
Run Code Online (Sandbox Code Playgroud)
这应该按预期工作:
>>> 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)
Run Code Online (Sandbox Code Playgroud)
请注意,这是一个快速而肮脏的草案(可能有几个错误).我只是想提出"一般的想法"如何在没有特殊套管的情况下解决每个算术运算中的类型.