diff --git a/mod_oop/3.4_11_box3d_math.py b/mod_oop/3.4_11_box3d_math.py new file mode 100644 index 0000000..55355c4 --- /dev/null +++ b/mod_oop/3.4_11_box3d_math.py @@ -0,0 +1,121 @@ +""" + https://stepik.org/lesson/701989/step/11?unit=702090 + + Объявите класс Box3D для представления прямоугольного параллелепипеда (бруска), объекты которого создаются командой: + +box = Box3D(width, height, depth) +где width, height, depth - ширина, высота и глубина соответственно (числа: целые или вещественные) + +В каждом объекте класса Box3D должны создаваться публичные атрибуты: + +width, height, depth - ширина, высота и глубина соответственно. + +С объектами класса Box3D должны выполняться следующие операторы: + +box1 = Box3D(1, 2, 3) +box2 = Box3D(2, 4, 6) + +box = box1 + box2 # Box3D: width=3, height=6, depth=9 (соответствующие размерности складываются) +box = box1 * 2 # Box3D: width=2, height=4, depth=6 (каждая размерность умножается на 2) +box = 3 * box2 # Box3D: width=6, height=12, depth=18 +box = box2 - box1 # Box3D: width=1, height=2, depth=3 (соответствующие размерности вычитаются) +box = box1 // 2 # Box3D: width=0, height=1, depth=1 (соответствующие размерности целочисленно делятся на 2) +box = box2 % 3 # Box3D: width=2, height=1, depth=0 +При каждой арифметической операции следует создавать новый объект класса Box3D с соответствующими значениями локальных атрибутов. + +P.S. В программе достаточно только объявить класс Box3D. На экран ничего выводить не нужно. + +""" + +from operator import add, sub, mul, truediv, floordiv, mod, xor + + +def add_ops(*ops): + def decorator(cls): + def make_methods(op): + def method_new(self, other): + return self.__class__(*self.map_op(op, other)) + + def method_ip(self, other): + self.values = self.map_op(op, other) + return self + + def method_r(self, other): + if isinstance(other, (int, float)): + return self.__class__(*map(lambda x: op(other, x), self.values)) + return self.__class__(*map(op, other.values, self.values)) + + 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 Box3D: + def __init__(self, width, height, depth): + self.width, self.height, self.depth = width, height, depth + + @property + def values(self): + return self.width, self.height, self.depth + + @values.setter + def values(self, values): + self.width, self.height, self.depth = values + + def __repr__(self): + return f"{self.__class__.__name__}{self.values!r}" + + def map_op(self, op, other): + if isinstance(other, (int, float)): + return map(lambda x: op(x, other), self.values) + return map(op, self.values, other.values) + + +def tests(): + box1 = Box3D(1, 2, 3) + box2 = Box3D(2, 4, 6) + assert ( + hasattr(box1, "depth") and hasattr(box1, "height") and hasattr(box1, "width") + ), "ошибка в атрибутах" + box = box1 + box2 + assert ( + box.depth == 9 and box.height == 6 and box.width == 3 + ), "ошибка при операции Box3D(1, 2, 3) + Box3D(2, 4, 6)" + box1 = Box3D(1, 2, 3) + box = box1 * 2 + assert ( + box.depth == 6 and box.height == 4 and box.width == 2 + ), "ошибка при операции box1 * 2 (каждая размерность умножается на 2)" + box = 3 * box2 + assert ( + box.depth == 18 and box.height == 12 and box.width == 6 + ), "ошибка при операции 3 * box2" + box = box2 - box1 + assert ( + box.depth == 3 and box.height == 2 and box.width == 1 + ), "ошибка при операции box2 - box1" + box = box1 // 2 + assert ( + box.depth == 1 and box.height == 1 and box.width == 0 + ), "ошибка при операции box1 // 2" + box = box2 % 3 + assert ( + box.depth == 0 and box.height == 1 and box.width == 2 + ), "ошибка при операции box2 % 3" + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + tests()