学习Python的__mul__()方法

1,088 阅读2分钟

语法

object.__mul__(self, other)

Python__mul__() 方法被调用来实现算术乘法运算*例如,为了评估表达式x * y ,Python试图调用x.__mul__(y)

我们称这种方法为*"* Dunder Method",即*"Double UnderscoreMethod"(也叫"Magic Method")*。

例子

在下面的例子中,你创建了一个自定义类Data ,并覆盖了__mul__() 方法,从而创建了一个新的Data 对象,其值是两个操作数ab 的乘积,类型为Data

class Data:

    def __init__(self, value):
        self.value = value
        
    def __mul__(self, other):
        return Data(self.value * other.value)


a = Data(21)
b = Data(2)
c = a * b

print(c.value)
# 42

你已经定义了dunder方法,所以产生的两个Data 对象的乘积本身就是一个Data 对象。

print(type(c))
# <class '__main__.Data'>

如果你没有定义__mul__() 方法,Python 会提出一个TypeError

如何解决TypeError:对*不支持的操作数类型

考虑下面的代码片段,你试图在没有定义dunder方法的情况下将两个自定义对象相乘__mul__()

class Data:

    def __init__(self, value):
        self.value = value


a = Data(21)
b = Data(2)
c = a * b

print(c.value)

在我的电脑上运行这个导致了以下错误信息。

Traceback (most recent call last):
  File "C:\Users\xcent\Desktop\code.py", line 9, in <module>
    c = a * b
TypeError: unsupported operand type(s) for *: 'Data' and 'Data'

这个错误的原因是,__mul__() dunder方法从未被定义过,而且默认情况下没有为自定义对象定义该方法。因此,为了解决TypeError: unsupported operand type(s) for * ,你需要在你的类定义中提供__mul__(self, other) 方法,如前所示。

class Data:

    def __init__(self, value):
        self.value = value
        
    def __mul__(self, other):
        return Data(self.value * other.value)

Python的__mul__与__rmul__对比

假设,你想将两个对象xy 相乘。

print(x * y)

Python 首先尝试调用左边对象的__mul__() 方法x.__mul__(y) 。但是这可能因为两个原因而失败。

  1. 方法x.__mul__() 首先没有实现,或者
  2. 方法x.__mul__() 已经实现,但是返回一个 NotImplemented 值,表明数据类型不兼容。

如果失败了,Python 试图通过调用y.__rmul__() 来解决这个问题,用于反向乘法的右侧运算符y 。如果这个方法被实现了,Python 知道它没有遇到非交换性操作的潜在问题。如果它只是执行y.__mul__(x) 而不是x.__mul__(y) ,那么如果乘法是非交换性的,就会引起错误。这就是为什么需要y.__rmul__(x) ,它表明乘法毕竟是可能的。

因此,x.__mul__(y)x.__rmul__(y) 之间的区别是,前者计算x * y 而后者计算y * x - 两者都调用定义在对象x 上的各自的乘法方法。