Умножение матрицы на месте __imatmul__ возвращает измененный объект - PullRequest
0 голосов
/ 13 июля 2020

Класс довольно простой:

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, я не могу заставить его преобразовать исходную матрицу - идентификаторы различаются:

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__?

1 Ответ

1 голос
/ 13 июля 2020

Ваша реализация __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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...