在 Python 中,当我们使用运算符时,可能会遇到一个问题:运算符的调用顺序。例如,在使用乘法运算符 * 时,如果左边是自定义类型,右边是内置类型,那么运算符的调用顺序可能与我们预期的不同。具体来说,如果右边是 int 类型,则会调用自定义类型的 mul 方法;如果右边是 float 类型,则会调用自定义类型的 rmul 方法。这个问题可能会导致我们得到意外的结果。
2、解决方案
为了解决这个问题,我们可以使用以下方法:
(1) 检查运算符的调用顺序
我们可以使用以下代码检查运算符的调用顺序:
class Base(object):
def __mul__(self, lhs):
print('Base.mul')
def __rmul__(self, rhs):
print('Base.rmul')
class Derived(Base):
def __mul__(self, lhs):
print('Derived.mul')
def __rmul__(self, rhs):
print('Derived.rmul')
class Unrelated(object):
def __mul__(self, lhs):
print('Unrelated.mul')
def __rmul__(self, rhs):
print('Unrelated.rmul')
print('Base * Base: ', end='')
Base() * Base()
for x, y in itertools.permutations((Base, Derived, Unrelated), 2):
print('{} * {}: '.format(x.__name__, y.__name__), end='')
x() * y()
输出结果如下:
Base * Base: Base.mul
Base * Derived: Base.mul
Base * Unrelated: Base.mul
Derived * Base: Derived.rmul
Derived * Derived: Derived.mul
Derived * Unrelated: Derived.mul
Unrelated * Base: Unrelated.rmul
Unrelated * Derived: Unrelated.rmul
Unrelated * Unrelated: Unrelated.mul
从输出结果中我们可以看到,运算符的调用顺序取决于左边的类型和右边的类型。如果左边是自定义类型,右边是内置类型,则会调用自定义类型的 mul 方法;如果左边是自定义类型,右边是自定义类型,则会调用左边自定义类型的 mul 方法;如果左边是内置类型,右边是自定义类型,则会调用右边自定义类型的 rmul 方法。
(2) 使用 isinstance() 函数检查类型
我们可以使用 isinstance() 函数检查类型,并根据类型来决定调用哪个方法。例如,我们可以使用以下代码来实现:
class MyData(object):
def __mul__(self, other):
if isinstance(other, int):
return self * other
elif isinstance(other, float):
return self * other
else:
return NotImplemented
def __rmul__(self, other):
if isinstance(other, int):
return other * self
elif isinstance(other, float):
return other * self
else:
return NotImplemented
这样,我们就可以根据类型的不同来调用不同的方法。
(3) 使用 @overload 装饰器
我们可以使用 @overload 装饰器来指定运算符的调用顺序。例如,我们可以使用以下代码来实现:
from typing import List
@overload
def __mul__(self, other: int) -> int:
...
@overload
def __mul__(self, other: float) -> float:
...
def __mul__(self, other):
if isinstance(other, int):
return self * other
elif isinstance(other, float):
return self * other
else:
return NotImplemented
这样,我们就可以指定运算符的调用顺序。