首页 > 解决方案 > 就地矩阵乘法 __imatmul__ 返回修改后的对象

问题描述

这个类很简单:

class Matrix(object):
    def __init__(self, values):
        self.values = values

    def __matmul__(self, other):
        return Matrix(Matrix.multiply(self.values, other.values))

    def __rmatmul__(self, other):
        return Matrix(Matrix.multiply(self.values, other.values))

    def __imatmul__(self, other):
        return self.__matmul__(other)

    @staticmethod
    def multiply(mat1, mat2):
        return [[sum(mat1 * mat2 for mat1, mat2 in zip(mat1_row, mat2_col))
                 for mat2_col in zip(*mat2)]
                for mat1_row in mat1]

    def __repr__(self):
        return f'<Matrix values="{self.values}">'

出于某种原因,在使用__imatmul__dunder 方法时,我无法使其转换初始矩阵 - ID 不同:

mat1 = Matrix([[11, 12], [13, 14]])
orig_id_mat1 = id(mat1)
print(f'mat1: {mat1}, id: {orig_id_mat1}')
mat2 = Matrix([[1, 2], [3, 4]])
orig_id_mat2 = id(mat2)
print(f'mat2: {mat2}, id: {orig_id_mat2}')

mat1 @= mat2
modif_id_mat1 = id(mat1)
print(f'mat1: {mat1}, id: {modif_id_mat1}')

输出:

mat1: <Matrix values="[[11, 12], [13, 14]]">, id: 24458192
mat2: <Matrix values="[[1, 2], [3, 4]]">, id: 24458384
mat1: <Matrix values="[[47, 70], [55, 82]]">, id: 24458608

的实施中应该改变什么__imatmul__

标签: pythonpython-3.xmatrix

解决方案


您的实现__imatmul__只是__matmul__. 它不会就地执行任何操作,因为您没有对其进行编码。

首先,您应该了解运营商的就地版本的作用。该表达式a @= b通常(但不总是)等价于a = type(a).__imatmul__(a, b)。这只是另一个函数调用。这样,您可以对创建新结果但保留名称的不可变对象执行“就地”操作。

你的调用__mult__就是这样做的:它创建并返回一个新对象,你用它替换你的矩阵。

就地进行操作的一种简单方法是

def __imatmul__(self, other):
    self.values = self.multiply(self.values, other.values)
    return self

您还可以定义__matmul____imatmul__使维护更容易:

def __matmul__(self, other):
    new = type(self)(self.values)
    return type(new).__imatmul__(new, other)

最后,您可能想要修复您的实现__rmatmul__

def __rmatmul__(self, other):
    return type(self).__matmul__(other, self)

推荐阅读