Как __setitem __ () работает с 4 аргументами? - PullRequest
0 голосов
/ 18 октября 2019

Я пишу класс Matrix с перегруженным оператором [].

Поскольку мой self.matrix, содержащий матрицу, является списком списков, метод __getitem__() согласно соглашению требует2 параметра self, index, возвращает список (строку), который может быть дополнительно подписан. Но как насчет __setitem__()? Разве он не должен принимать только 3 параметра по определению? Я попробовал это с 4 параметрами, и это как-то работает нормально. Я знаю, что аргумент кортежа может быть передан для доступа к элементам матрицы, но я хотел бы знать, почему это работает с 4 параметрами? Это неопределенное поведение? Если я напишу m_obj[rindex][cindex] = val, это будет работать безупречно!

Также, если я просто сделаю m_obj[rindex] = val, я получу следующую ошибку:

Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    a[1] = 1
TypeError: __setitem__() missing 1 required positional argument: 'val'

Но это действительно то, чего я хочу, за исключением того, что отсутствующий позиционный аргумент был cindex, а не val.

Напротив, если я добавлю дополнительный параметр к __getitem__(), код не будет работать:

 def __getitem__(self, rindex, cindex):
        return self.matrix[rindex][cindex]

И я получаю эту ошибку как при получении, так и при установке:

>>> a[1][1] = 1
Traceback (most recent call last):
  File "<pyshell#21>", line 1, in <module>
    a[1][1] = 1
TypeError: __getitem__() missing 1 required positional argument: 'cindex'

Вот код:


class DimensionError(BaseException):
    pass


class Matrix:
    def __init__(self, rows, cols):
        self.rows = rows
        self.cols = cols
        self.matrix = [[] for i in range(self.rows)]
        for i in range(self.rows):
            self.matrix.app
            for j in range(self.cols):
                self.matrix[i].append(0)

    def __str__(self):  
        matrep = ''
        for i in self.matrix:
            matrep += str(i) + '\n'
        return matrep

    def __getitem__(self, index):
        return self.matrix[index]

    def __setitem__(self, rindex, cindex, val):
        self.matrix[rindex][cindex] = val

    def __add__(self, secmat):
        if self.rows != secmat.rows or self.cols != secmat.cols:
            raise DimensionError('Incompatible Matrices for Addition')
        newmat = Matrix(self.rows, self.cols)
        for i in range(self.rows):
            for j in range(self.cols):
                newmat[i][j] = self[i][j] + secmat[i][j]
        return newmat

    def __sub__(self, secmat):
        if self.rows != secmat.rows or self.cols != secmat.cols:
            raise DimensionError('Incompatible Matrices for Subtraction')
        newmat = Matrix(self.rows, self.cols)
        for i in range(self.rows):
            for j in range(self.cols):
                newmat[i][j] = self[i][j] - secmat[i][j]
        return newmat

    def __matmul__(self, secmat):
        if self.cols != secmat.rows:
            raise DimensionError('Incomatible Matrices for Multiplication. Product is undefined')
        newmat = Matrix(self.rows, secmat.cols)
        for i in range(self.rows):
            for j in range(secmat.cols):
                for k in range(secmat.rows):
                    newmat[i][j] += (self[i][k] * self[k][j])
        return newmat

    def __mul__(self, secmat):
            return self.__matmul__(secmat)


#Driver
a = Matrix(2, 2)
b = Matrix(2, 2)
print('Enter elements of first matrix:')
for i in range(a.rows):
    for j in range(a.cols):
        a[i][j] = int(input(f'Enter element [{i}{j}] >>>'))

print('Enter elements of second matrix:')
for i in range(b.rows):
    for j in range(b.cols):
        b[i][j] = int(input(f'Enter element [{i}{j}] >>>'))

print('Matrix a: ')
print(a)
print('Matrix b: ')
print(b)
print('Multiplication is:')
print(a @ b) # or a * b

Я пробовал это в Python 2.7 без f-строк и оператора @, и он работает точно так же.

Может кто-нибудь объяснить, что происходит под капотом?

Заранее спасибо!

1 Ответ

1 голос
/ 18 октября 2019

Это не работает. Он вообще не вызывается.

Когда вы делаете m_obj[rindex][cindex] = val, Python вызывает __getitem__, чтобы получить значение m_obj[rindex]. Затем он вызовет метод __setitem__ любого значения. Вы можете доказать это себе, поместив отпечаток в свой метод.

...