285 lines
15 KiB
Python
285 lines
15 KiB
Python
|
"""
|
|||
|
https://stepik.org/lesson/701994/step/12?unit=702095
|
|||
|
|
|||
|
Объявите класс Matrix (матрица) для операций с матрицами.
|
|||
|
|
|||
|
Объекты этого класса должны создаваться командой:
|
|||
|
m1 = Matrix(rows, cols, fill_value)
|
|||
|
где rows, cols - число строк и столбцов матрицы; fill_value - заполняемое начальное значение элементов матрицы (должно быть число: целое или вещественное).
|
|||
|
>>> rows, cols, fill_value = 4, 2, 0
|
|||
|
>>> m1 = Matrix(rows, cols, fill_value)
|
|||
|
|
|||
|
Если в качестве аргументов передаются не числа, то генерировать исключение:
|
|||
|
raise TypeError('аргументы rows, cols - целые числа; fill_value - произвольное число')
|
|||
|
>>> m1 = Matrix("тест", cols, fill_value)
|
|||
|
Traceback (most recent call last):
|
|||
|
...
|
|||
|
TypeError: аргументы rows, cols - целые числа; fill_value - произвольное число
|
|||
|
|
|||
|
Также объекты можно создавать командой:
|
|||
|
m2 = Matrix(list2D)
|
|||
|
где list2D - двумерный список (прямоугольный), состоящий из чисел (целых или вещественных).
|
|||
|
>>> list2D = [[1, 2], [3, 4], [5, 6], [7, 8]]
|
|||
|
>>> m2 = Matrix(list2D)
|
|||
|
|
|||
|
Если список list2D не прямоугольный, или хотя бы один из его элементов не число, то генерировать исключение командой:
|
|||
|
raise TypeError('список должен быть прямоугольным, состоящим из чисел')
|
|||
|
>>> m2 = Matrix([[1, 2], [3], [4, 5], [6, 7, 8]])
|
|||
|
Traceback (most recent call last):
|
|||
|
...
|
|||
|
TypeError: список должен быть прямоугольным, состоящим из чисел
|
|||
|
|
|||
|
|
|||
|
Для объектов класса Matrix должны выполняться следующие команды:
|
|||
|
matrix = Matrix(4, 5, 0)
|
|||
|
res = matrix[0, 0] # возвращается первый элемент матрицы
|
|||
|
matrix[indx1, indx2] = value # элементу матрицы с индексами (indx1, indx2) присваивается новое значение
|
|||
|
>>> matrix = Matrix(4, 5, 0)
|
|||
|
>>> matrix[0, 0] = 42
|
|||
|
>>> matrix[0, 0]
|
|||
|
42
|
|||
|
|
|||
|
Если в результате присвоения тип данных не соответствует числу, то генерировать исключение командой:
|
|||
|
raise TypeError('значения матрицы должны быть числами')
|
|||
|
Если указываются недопустимые индексы матрицы (должны быть целыми числами от 0 и до размеров матрицы), то генерировать исключение:
|
|||
|
raise IndexError('недопустимые значения индексов')
|
|||
|
|
|||
|
Также с объектами класса Matrix должны выполняться операторы:
|
|||
|
matrix = m1 + m2 # сложение соответствующих значений элементов матриц m1 и m2
|
|||
|
matrix = m1 + 10 # прибавление числа ко всем элементам матрицы m1
|
|||
|
matrix = m1 - m2 # вычитание соответствующих значений элементов матриц m1 и m2
|
|||
|
matrix = m1 - 10 # вычитание числа из всех элементов матрицы m1
|
|||
|
|
|||
|
Во всех этих операция должна формироваться новая матрица с соответствующими значениями.
|
|||
|
Если размеры матриц не совпадают (разные хотя бы по одной оси), то генерировать исключение командой:
|
|||
|
raise ValueError('операции возможны только с матрицами равных размеров')
|
|||
|
|
|||
|
Пример для понимания использования индексов (эти строчки в программе писать не нужно):
|
|||
|
|
|||
|
mt = Matrix([[1, 2], [3, 4]])
|
|||
|
res = mt[0, 0] # 1
|
|||
|
res = mt[0, 1] # 2
|
|||
|
res = mt[1, 0] # 3
|
|||
|
res = mt[1, 1] # 4
|
|||
|
|
|||
|
P.S. В программе нужно объявить только класс. Выводить на экран ничего не нужно.
|
|||
|
|
|||
|
---
|
|||
|
>>> Matrix(2, 2) - 2
|
|||
|
Matrix([[-2, -2], [-2, -2]])
|
|||
|
"""
|
|||
|
|
|||
|
from functools import singledispatchmethod
|
|||
|
from operator import add, floordiv, mod, mul, sub, truediv, xor
|
|||
|
|
|||
|
|
|||
|
def add_ops(*ops):
|
|||
|
def decorator(cls):
|
|||
|
def make_methods(op):
|
|||
|
def method_new(self, other):
|
|||
|
return self.__class__(self.mapped(op, other))
|
|||
|
|
|||
|
def method_ip(self, other):
|
|||
|
self.data = self.mapped(op, other)
|
|||
|
return self
|
|||
|
|
|||
|
def method_r(self, other):
|
|||
|
if isinstance(other, (int, float)):
|
|||
|
return self.__class__(
|
|||
|
[
|
|||
|
*map(
|
|||
|
lambda row: [*map(lambda x: op(other, x), row)],
|
|||
|
self.data,
|
|||
|
)
|
|||
|
]
|
|||
|
)
|
|||
|
return NotImplemented
|
|||
|
|
|||
|
return {
|
|||
|
f"__{op.__name__}__": method_new,
|
|||
|
f"__i{op.__name__}__": method_ip,
|
|||
|
f"__r{op.__name__}__": method_r,
|
|||
|
}
|
|||
|
|
|||
|
for op in ops:
|
|||
|
for name, method in make_methods(op).items():
|
|||
|
setattr(cls, name, method)
|
|||
|
return cls
|
|||
|
|
|||
|
return decorator
|
|||
|
|
|||
|
|
|||
|
@add_ops(add, sub, mul, truediv, floordiv, xor, mod, pow)
|
|||
|
class Matrix:
|
|||
|
@singledispatchmethod
|
|||
|
def __init__(self, rows, cols, fill_value=0):
|
|||
|
args_valid = (
|
|||
|
isinstance(rows, int)
|
|||
|
and isinstance(cols, int)
|
|||
|
and isinstance(fill_value, (int, float))
|
|||
|
)
|
|||
|
if not args_valid:
|
|||
|
raise TypeError(
|
|||
|
"аргументы rows, cols - целые числа; fill_value - произвольное число"
|
|||
|
)
|
|||
|
self.rows, self.cols = rows, cols
|
|||
|
self.data = [[fill_value for _ in range(cols)] for _ in range(rows)]
|
|||
|
|
|||
|
@__init__.register(list)
|
|||
|
@__init__.register(tuple)
|
|||
|
def _from_list_tuple(self, data):
|
|||
|
data = data or [[]]
|
|||
|
if not isinstance(data[0], (list, tuple)):
|
|||
|
raise TypeError("список должен быть прямоугольным, состоящим из чисел")
|
|||
|
|
|||
|
self.rows, self.cols = len(data), len(data[0])
|
|||
|
self.data = []
|
|||
|
for row in data:
|
|||
|
if len(row) != self.cols:
|
|||
|
raise TypeError("список должен быть прямоугольным, состоящим из чисел")
|
|||
|
new_row = []
|
|||
|
for value in row:
|
|||
|
if not isinstance(value, (int, float)):
|
|||
|
raise TypeError(
|
|||
|
"список должен быть прямоугольным, состоящим из чисел"
|
|||
|
)
|
|||
|
new_row.append(value)
|
|||
|
self.data.append(new_row)
|
|||
|
|
|||
|
def __repr__(self):
|
|||
|
return f"{self.__class__.__name__}({self.data!r})"
|
|||
|
|
|||
|
def __len__(self):
|
|||
|
return self.rows
|
|||
|
|
|||
|
def __iter__(self):
|
|||
|
return (
|
|||
|
(self.cells[row][col].data for col in range(self.cols))
|
|||
|
for row in range(self.rows)
|
|||
|
)
|
|||
|
|
|||
|
def validate_index(self, index):
|
|||
|
if not isinstance(index, tuple):
|
|||
|
raise IndexError("недопустимые значения индексов")
|
|||
|
row, col = index
|
|||
|
if (
|
|||
|
not isinstance(row, int)
|
|||
|
or not 0 <= row < self.rows
|
|||
|
or not isinstance(col, int)
|
|||
|
or not 0 <= col < self.cols
|
|||
|
):
|
|||
|
raise IndexError("недопустимые значения индексов")
|
|||
|
return row, col
|
|||
|
|
|||
|
def __getitem__(self, index):
|
|||
|
row, col = self.validate_index(index)
|
|||
|
return self.data[row][col]
|
|||
|
|
|||
|
def __setitem__(self, index, new_value):
|
|||
|
row, col = self.validate_index(index)
|
|||
|
if not isinstance(new_value, (int, float)):
|
|||
|
raise TypeError("значения матрицы должны быть числами")
|
|||
|
self.data[row][col] = new_value
|
|||
|
|
|||
|
def validate_size(self, other):
|
|||
|
if not isinstance(other, self.__class__):
|
|||
|
raise NotImplementedError
|
|||
|
if (self.rows, self.cols) != (other.rows, other.cols):
|
|||
|
raise ValueError("операции возможны только с матрицами равных размеров")
|
|||
|
|
|||
|
def mapped(self, op, other):
|
|||
|
if isinstance(other, (int, float)):
|
|||
|
return [*map(lambda row: [*map(lambda x: op(x, other), row)], self.data)]
|
|||
|
|
|||
|
self.validate_size(other)
|
|||
|
return [
|
|||
|
*map(
|
|||
|
lambda self_row, other_row: [
|
|||
|
*map(
|
|||
|
lambda self_x, other_x: op(self_x, other_x), self_row, other_row
|
|||
|
)
|
|||
|
],
|
|||
|
self.data,
|
|||
|
other.data,
|
|||
|
)
|
|||
|
]
|
|||
|
|
|||
|
|
|||
|
def tests():
|
|||
|
# 10x = https://stepik.org/lesson/701994/step/12?discussion=5990560&unit=702095
|
|||
|
code = (
|
|||
|
b"Y-w|JGDILfAX{58EFdynEFfDmEFd&pEFfDoEFd;4AU9oI3UqRLItm~lARu#eAUz;WVRUk7cqnX"
|
|||
|
+ b"Xb96F9DGFtHV`Xr3AXIs9WkqswZ*n>cARr(hVRLh3a&#b6a&=`2Wo&b0Itm~lARu9Lb7gXLAVy(q"
|
|||
|
+ b"b7d?bBGA3iwII=f(6i9B(7n*L(SXpn(SXpt(6Z35(7VvS(Sgy7AketcfzZ0pyU~u(htRdqz0kPOw"
|
|||
|
+ b"IEb^aAieua&K}V(6rFI(T^a|z0kEF(7(}u(T~u)(7w@w(6i9K(7Vx$(7n*U(6i9KAkl%)ztFhRfz"
|
|||
|
+ b"Z0puprQ~AkezdzR<nVfzg7|fYF1{y3vBrzR`ftwIEGlbaH8UA_@v@X>)WkL?AsNTU#+KAX{BsEFf"
|
|||
|
+ b"DmEFd&pEFfDoEFd;rT?%w^c{&OpARr)fbRaz-O<{C$X?Q4XX>)WkL@5eocw=R7bRblDaAieua&K}"
|
|||
|
+ b"v3LqdLAYpTJWpZ>NRC0A?3T13_WjYEVARr)Nb8}^KbRb4yY;$ESAR^Gc(6u1ZfzY$iwa~rLwb6jk"
|
|||
|
+ b"xY2;nzR<GJu+Y2EzR`ivj3Cgs(Sgvq(7Vx&(TC8r(7n*O(6t~`d2nS#a&m8SAkehXyU~vz(Sgvv("
|
|||
|
+ b"74fo(7MpDAke+gwII;A(6=DbhtRmufzY+kyCBfAAkezdzR<nVfzg7|fYF1{y3vBrzR`ftwIEGlba"
|
|||
|
+ b"H8UA_@w0a(OxmARr(hb95j*AWdO(a%p%dCov~1ATlf<FewUUcw=R7bRblDaAieua&K}v3LqdLAYp"
|
|||
|
+ b"TJWpZ>NRC0A?3T13_WjYEVARr)Nb8}^KbRb4yY;$ESAR^Gc(6u1ZfzY$iwa~rLwb6jkxY2;nzR<G"
|
|||
|
+ b"Ju+Y2EzR`ivj3Cgs(Sgvq(7Vx&(TC8r(7n*O(6t~`d2nS#a&m8SAkehXyU~vz(7n*LAkl}=xY2>o"
|
|||
|
+ b"yU@PSveAptg&@$d(SXpi(Sy*u(6!LL(Sp#v(6S)VvLMj9(7w>U(Sgx|(SXr|(7Mrr(7w@t(6t~<V"
|
|||
|
+ b"RUk7cp?f4Y-w|JGDILfAX{58EFdynEFfDmEFd&pEFfDoEFd;rT?%bsbaH8UAUz;WVRUk7cqnXXb9"
|
|||
|
+ b"6F9DGFh8b7gXLAZ=lEa%p&5GAtl5T_8O@AT}%@BGA3iwa~KAwb6jkz0kfO(7w@v(SXpf(6P|I(Sp"
|
|||
|
+ b"#h(7Pbey3oGRz0rZug3*A{gV4Isg3!LvfFRJg(7VvMAYWf+WprtDWo=(yA_@v^VRUk7cpyC>O<{C"
|
|||
|
+ b"$X?Q3!EFd*3ATcm03So0|WpZ>NZDDkBX?R;REFd&pAU!=GF)%D3BGA3iwa~KAwb6jkz0kfO(7w@v"
|
|||
|
+ b"(SXpf(6P|I(Sp#h(7Pbey3oGRz0rZug3*A{gV4Isg3!LvfFRJg(7VvMAYWf+WprtDWo=(yA_@w0a"
|
|||
|
+ b"(OxmARr(hb|5_<ZDDkBX?R;REFdj0T?%D*V`Xr3AW3dyWq3t$a&K}v3LqdLAYpTJWpZ>NRC0A?3T"
|
|||
|
+ b"13_WjYEVARr)Nb8}^KbRb4yY;$ESAR^Gc(6u1ZfzY$iwa~rLwb6jkxY2;nzR<GJu+Y2EzR`ivj3C"
|
|||
|
+ b"gs(Sgvq(7Vx&(TC8r(7n*O(6t~*Ze(S6MRIa)av}-}baHt*3LqdLAa)=<AZ=lEa%p&5Com^0AT(V"
|
|||
|
+ b"HWq4y{aC9I^Ze(S6MRIa)aykkiARr)Nb8}^KbRbl6b!7@=Y;$Eg3LqdLAYpTJWpZ>NMqzAoWh@{f"
|
|||
|
+ b"(7n*LAkl%)v(UBBz0kGMfY7+nfY83sve2;5yU@PTfzga0(74fo(7MpO(T>rF(6!LL(74dGAW3dyW"
|
|||
|
+ b"q3t$a&K}X3JPsubaH8UTQDpjFkK)$AU6tOb8}^KbRcbEbaH8UTQDpjFkK)$Js>wMAR^Gc(6!LA(6"
|
|||
|
+ b"!Nk(7n*UAke<ig3*A`u+Xv4zR`lvu+Y08Ute=&bZK;DZC_s^3JP>`c{&OpARr)ZVRUk7cv~<mATV"
|
|||
|
+ b"7ZJs>AxCkkbFV`Xr3AXIs9WkqswZ*n>cARr(hVRLh3a&#b6a&=`2Wo&b0Itm~lARu9Lb7gXLAVy("
|
|||
|
+ b"qb7d?bBGA3iwII=f(6i9B(7n*L(SXpn(SXpt(6Z35(7VvS(Sgy7AketcfzZ0pyU~u(htRdqz0kPO"
|
|||
|
+ b"wIEb^aAieua&K}V(6S(3Uvp)2X>?_6Utb~$3T-hUJs?eCbaH8UC|g@GEFdynEFfDmEFd&pT`3A}G"
|
|||
|
+ b"9W!5O<{C$X?Q4GTQMvkF<mSmTQMvkF<mSmTQMvkF<o6L3JP>`c{&OpARr)ZVRUk7cpyC>Z80D#AZ"
|
|||
|
+ b";=VWq4y{aC9J6VQh6}MRIa)aykkiARr)Nb8}^KbRbl6b!7@=Y;$Eg3LqdLAYpTJWpZ>NMqzAoWh@"
|
|||
|
+ b"{f(7n*LAkl%)v(UBBz0kGMfY7+nfY83sve2;5yU@PTfzga0(74fo(7MpO(T>rF(6!LL(74dGAXZ^"
|
|||
|
+ b")b!A0za&K}V(7(}u(6}JcfzZ3qzR<SNwa~rLxX`#D(7e#F(Sp%{(74ftAkl!(u+X>Az0r%&g&@&@"
|
|||
|
+ b"(6G?A(7e#K(SXpt(6S;53T-hUJs?eCbaH8UC|g@GEFdynEFfDmEFd&pT`3A}G9W!5O<{C$X?Q4GT"
|
|||
|
+ b"QMvkF<mSmTQMvkF<o6L3T<I@a%p%VJs@o{AS)nkG74dHb7gXLAZc@HZgX^DZewLAZDDkBX?QFkO<"
|
|||
|
+ b"{C$X?Q6tAR^Gd(7({N(SXpf(T32t(T^a}fzZ3qzR<SNwa~rLxY3Uw(7e#F(Sp%{(74ftAkehXzR<"
|
|||
|
+ b"hSw$Q!MuprQ~(7w>O(6Z5h(6G^o(6G^h(TpI`jnKN#x6rlFywJbUyU~x)fFRJi(7VvE(Sgx{(6As"
|
|||
|
+ b")VRUk7cp?g6b8}^KbRcbEbaH8UTQMvkF<l@%Js>qKAR^Gc(6!LA(6!Nk(7n*UAke<ig3*A`u+Xv4"
|
|||
|
+ b"zR`lvu+Y2EuprRB(7({N(SXpf(T32t(T^a}fzZ3qzR<SNwa~rLxY3Uw(7e#F(Sp%{(74ftA_`%1b"
|
|||
|
+ b"7gXLAZ;;QF)Sc4T_8O@AT%IhZe$>BF<US!ATeDaJv|^YAYpD~AZ;>RF)Sc4T_8O@ATc0Z3LqdLAR"
|
|||
|
+ b"r(hVQyp~Z8BRhEFdslAU!=GF)Sb=(74fo(S^{y(6rFK(TmWvAke(fu+f6ifY7+nhS7^4(7n*LAke"
|
|||
|
+ b"hXzR<hSw$Q!Niy+Xv(6!LL(T~xB(Tvf7(T^a|ztMouxFFEJ(7({N(SXpf(T32t(6}JcfzZ3qzR<S"
|
|||
|
+ b"Nwa~rLxY3Uy3JPs8AUz;WVRUk7cqlR~ATlf<F)0dZWM6GDUvF$=AUz;yWGHPhDGF^eAUz;WVRUk7"
|
|||
|
+ b"cqlR~ATlf<F)0ddF(5r4Z80D#AZ;=VX=Gn*F<)+FcOX3=X=EsEF)0dRb8}^KbRcPDUu`j8Z){{BA"
|
|||
|
+ b"w3{zWM6GDUv6c0EFdD#vLMlb(6!LF(Sy*t(Tvf8(6G^h(6u1YzR<tWwb6jku+fIlxX`#D(Sgvr(7"
|
|||
|
+ b"w>N(6!LL(74f$AkehXzR<hSw$QcEy&%zn(7w>O(6rF7(6Z35(Sp&8(SgyAAkdxAp3suetI(Ms(T&"
|
|||
|
+ b"i$(6`XF(7e#U(7Vx((SRV(y3o7Ou+f3hfzYrZO<{C$X?P+E3T<I@a%p%VJs?eCbaH8UC^9S{GAtl"
|
|||
|
+ b"4DGF^MJs@pibaH8UAS)m-FbZLFb7gXLAZ=lEa%p&5Ff1T2T_8O@AZ=lEa%p&5F)Sc4T_8O@ATTT-"
|
|||
|
+ b"BG9<efzgG~zR<MLz0r%%wII;E(6G^h(SXpn(S~6l(7n*LAkehXzR<hSw$Q!MuprR9(6!LL(T~xB("
|
|||
|
+ b"Tvf7(T^a|ztMouxFFEJ(7({N(SXpf(T32t(6}JcfzZ3qzR<SNwa~rLxY3UwV<6Fo(74fo(7VvS(7"
|
|||
|
+ b"YlFVRLh3a&#bVTQDpjFkK)$Js>eKEFdD#z0kGLve32BfY80rz97)P(Sp%{(6G?4(7w@v(6G?E(6A"
|
|||
|
+ b"uTzR<tWwb6jku+fIlxY3Uw(Sgvr(7w>N(6!LL(74f$Ake(fu+f6ifY7+nhS7^4(Sab*htRmufzZ3"
|
|||
|
+ b"qzR<iP3JPs8AUz;WVRUk7cqlR~ATlf<F)0ddG9W!5O<{C$X?Q4GTQDpjF<mSmTQMvkFkM|K3Tb3z"
|
|||
|
+ b"ZggpMd0%Z|baH8UAUz;$F(54<Z89JrBOuVU(7w>S(6-RM(6AuTztFzWyU~NuhtRmug3*l8fzgj3("
|
|||
|
+ b"6!LC(74dO(74fu(7n*G(T^a|ywI@Gg3*A`xY35tunJ*wb7gXLAZ;;QFf1T2T_8O@ATc0eZe$>BF<"
|
|||
|
+ b"UV#ATeDaJv|^XAYpD~AZ;>RFf1T2T_8O@ATS_Y3LqdLARr(hVQyp~Z8BRhEFdvmAU!=GF)Sb=(74"
|
|||
|
+ b"fo(S^{y(6rFK(TmWvAke(fu+f6ifY7+nhS7^4(7n*LAkehXzR<hSw$Q!Niy+Xv(6!LL(T~xB(Tvf"
|
|||
|
+ b"7(T^a|ztMouxFFEJ(7({N(SXpf(T32t(6}JbveApthtRmug3z$gz0kPPk0J_Tb8}^KbRcPDWo~q7"
|
|||
|
+ b"ba`KGVRUk7cv~<mATV7ZJv|^XAYpD~AZcV}ZggpMd0%Z|baH8UTQMvkF<l@%Js>eGAR^Gc(6!LA("
|
|||
|
+ b"6!Nk(7n*UAke<ig3*A`u+Xv4zR`lvu+Y2EuprRB(7({N(SXpf(T32t(T^a|veApthtRmug3z$gz0"
|
|||
|
+ b"kPPk08*z(6G^h(SXpn(S{-l3T<I@a%p%VJs?eCbaH8UC^9S{GAtl5DGF^MJs@pibaH8UAT1y<3So"
|
|||
|
+ b"0|WpZ>NZDDkBX?R;OEFdslAU!=GZDDkBX?R;PEFdvmAU!=GF)Sb=(74fo(S^{y(6rFK(TmWvAke("
|
|||
|
+ b"fu+f6ifY7+nhG8Jkz0kEF(6rFL(7VvK(7n*GAke(fwa~rMkI{nBjM0J7k08*$(SXpnAke<hztFYO"
|
|||
|
+ b"fY7kfhS0dsxFFE7(TmZC(74fp(6G?G(74f$AY&lWhtRmufzZ3qzR<iP3So0|WpZ>NZCfxbATV7ZJ"
|
|||
|
+ b"v|_8TQMvkF<l@%Js>bFAR^Gc(6!LA(6!Nk(7n*UAke<ig3*A`u+Xv4zR`lvu+Y2EuprRB(7({N(S"
|
|||
|
+ b"Xpf(T32t(T^a|veApthtRmug3z$gz0kPPk08;9(74fo(7VvEAketbw;<5G(6G^h(SXpn(T35BA^"
|
|||
|
)
|
|||
|
exec(__import__("base64").b85decode(code))
|
|||
|
|
|||
|
|
|||
|
if __name__ == "__main__":
|
|||
|
import doctest
|
|||
|
|
|||
|
doctest.testmod()
|
|||
|
tests()
|