3. 增强赋值算术运算符重载

增强赋值算术运算符重载的方法

方法名和参数
运算符和表达式
说明
__iadd__(self, other)
self += other
加法
__isub__(self, other)
self -= other
减法
__imul__(self, other)
self *= other
乘法
__itruediv__(self, other)
self /= other
除法
__ifloordiv__(self, other)
self //= other
整数(地板除)
__imod__(self, other)
self %= other
求余(取模)
__ipow__(self, other)
self **= other
__imatmul__(self, other)
self @= other
矩阵乘法

示例

# 增强赋值算术运算符重载 示例
# http://weimingze.com

class Vector3D:
    '''用于描述三维向量的类!,x,y,z分别是向量的坐标位置!'''
    def __init__(self, x, y, z):
        self.x, self.y, self.z = x, y, z

    def __repr__(self):
        return f'Vector3D({self.x},{self.y},{self.z})'

    def __mul__(self, other):
        return Vector3D(
            self.x * other, self.y * other,
            self.z * other)

    def __imul__(self, other):
        self.x *= other
        self.y *= other
        self.z *= other
        return self

v1 = Vector3D(1, 2, 3)
print("v1:", v1)
print(id(v1))
v1 *= 3  # v1.__imul__(3)  # v1 = v1.__mul__(3)
print('v1:', v1)
print(id(v1))

运行结果

v1: Vector3D(1,2,3)
4358500240
v1: Vector3D(3,6,9)
4358500240

去掉 __imul__ 方法,程序运行结果相同,只是ID会有变化。此时 v1 *= 3 后 v1绑定的不是原对象。

示例

# 增强赋值算术运算符重载 示例
# http://weimingze.com

class Vector3D:
    '''用于描述三维向量的类!,x,y,z分别是向量的坐标位置!'''
    def __init__(self, x, y, z):
        self.x, self.y, self.z = x, y, z

    def __repr__(self):
        return f'Vector3D({self.x},{self.y},{self.z})'

    def __mul__(self, other):
        return Vector3D(
            self.x * other, self.y * other,
            self.z * other)

v1 = Vector3D(1, 2, 3)
print("v1:", v1)
print(id(v1))
v1 *= 3  # v1.__imul__(3)  # v1 = v1.__mul__(3)
print('v1:', v1)
print(id(v1))

运行结果

v1: Vector3D(1,2,3)
4404751936
v1: Vector3D(3,6,9)
4406038032

增强赋值算术运算符的运算规则说明

以增强赋值算术运算符 x += y 为例,此运算符会优先调用 x.__iadd__(y) 方法,如果没有__iadd__() 方法时会将增强赋值运算拆解为 x = x + y,然后调用 x = x.__add__(y) 方法;如果再不存在 __add__() 方法则会触发 TypeError 异常。

其它增强赋值算术运算符也具有相同的规则。

问题

以下两个程序打印结果是什么?为什么不一样?

f1 函数传入列表的程序运行:

# ---  以下用列表 ---
L = [1, 2, 3]
def f1(lst):
    lst += [4, 5, 6]
f1(L)
print(L)  # [1, 2, 3, 4, 5, 6]

f1 函数传入元组的程序运行:

# ---  以下用元组 ---
L = (1, 2, 3)
def f1(lst):
    lst += (4, 5, 6)
f1(L)
print(L)  # (1, 2, 3)