我有一个简单的类,可以帮助对向量进行数学运算(即数字列表)。我的Vector
可以与Vector
或标量(float
或int
)的其他实例相乘。
在其他更强类型的语言中,我会创建一种方法来将两个vector
和一个单独的方法相乘,以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中这样做的正确方法是什么?
答案 0 :(得分:17)
您还需要实施__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
通常是两种不同的结果,因此Matrix.__rmul__(m, n) != Matrix.__mul__(m, n)
; __rmul__
必须做一些额外的工作才能产生正确的答案。
答案 1 :(得分:8)
有special methods for reversed operations:
__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)
的转换:
declare @startdate date;
这应该按预期工作:
@startdate := DATEFROMPARTS(....
请注意,这是一个快速而肮脏的草稿(可能有几个错误)。我只是想提出一般的想法"如何在没有特殊套管的情况下解决每个算术运算中的类型。