From 6ef8a00edc71ad8374d7edc89547a2486d530dd8 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 10 Apr 2024 16:00:37 +0300 Subject: [PATCH] + 3.1_11 --- mod_oop/3.1_11_dimensions.py | 165 +++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 mod_oop/3.1_11_dimensions.py diff --git a/mod_oop/3.1_11_dimensions.py b/mod_oop/3.1_11_dimensions.py new file mode 100644 index 0000000..3492743 --- /dev/null +++ b/mod_oop/3.1_11_dimensions.py @@ -0,0 +1,165 @@ +""" + https://stepik.org/lesson/701986/step/11?unit=702087 + + Объявите в программе класс Dimensions (габариты) с атрибутами: + +MIN_DIMENSION = 10 +MAX_DIMENSION = 1000 + +>>> (Dimensions.MIN_DIMENSION, Dimensions.MAX_DIMENSION) +(10, 1000) + +Каждый объект класса Dimensions должен создаваться командой: +d3 = Dimensions(a, b, c) # a, b, c - габаритные размеры +>>> d3 = Dimensions(10, 10, 10) + +и содержать локальные атрибуты: +__a, __b, __c - габаритные размеры (целые или вещественные числа). + +Для работы с этими локальными атрибутами в классе Dimensions следует прописать следующие объекты-свойства: +a, b, c - для изменения и считывания соответствующих локальных атрибутов __a, __b, __c. +>>> (d3.a, d3.b, d3.c) +(10, 10, 10) +>>> [*map(lambda x: getattr(Dimensions, x).__class__, "abc")] +[, , ] + +При изменении значений __a, __b, __c следует проверять, что присваиваемое значение число в диапазоне [MIN_DIMENSION; MAX_DIMENSION]. Если это не так, то новое значение не присваивается (игнорируется). + +С помощью магических методов данного занятия запретить создание локальных атрибутов MIN_DIMENSION и MAX_DIMENSION в объектах класса Dimensions. При попытке это сделать генерировать исключение: +raise AttributeError("Менять атрибуты MIN_DIMENSION и MAX_DIMENSION запрещено.") +>>> d3.MIN_DIMENSION = 4 +Traceback (most recent call last): + ... +AttributeError: Менять атрибуты MIN_DIMENSION и MAX_DIMENSION запрещено. +>>> d3.MAX_DIMENSION = 400 +Traceback (most recent call last): + ... +AttributeError: Менять атрибуты MIN_DIMENSION и MAX_DIMENSION запрещено. + +Пример использования класса (эти строчки в программе писать не нужно): +d = Dimensions(10.5, 20.1, 30) +d.a = 8 +d.b = 15 +a, b, c = d.a, d.b, d.c # a=10.5, b=15, c=30 +d.MAX_DIMENSION = 10 # исключение AttributeError + +>>> d = Dimensions(10.5, 20.1, 30) +>>> d.a = 8 +>>> d.b = 15 +>>> (d.a, d.b, d.c) +(10.5, 15, 30) + +P.S. В программе нужно объявить только класс Dimensions. На экран ничего выводить не нужно. +""" + + +def make_properties(*names): + def decorator(cls): + def prop(private_name: str): + def getter(self): + return getattr(self, private_name) + + def setter(self, value): + return setattr(self, private_name, value) + + return getter, setter + + for name in names: + setattr(cls, name, property(*prop(f"_{cls.__name__}__{name}"))) + return cls + + return decorator + + +@make_properties(*"abc") +class Dimensions: + MIN_DIMENSION = 10 + MAX_DIMENSION = 1000 + + def __init__(self, a, b, c): + self.a, self.b, self.c = a, b, c + + def __setattr__(self, name, value): + if name in ["MIN_DIMENSION", "MAX_DIMENSION"]: + raise AttributeError( + "Менять атрибуты MIN_DIMENSION и MAX_DIMENSION запрещено." + ) + if not self.MIN_DIMENSION <= value <= self.MAX_DIMENSION: + return + super().__setattr__(name, value) + + +def tests(): + # из https://stepik.org/lesson/701986/step/11?discussion=7391213&unit=702087 + # TEST-TASK___________________________________ + x = Dimensions(10.0, 20, 30) + # проверка что в классе прописаны объекты свойства a-b-c + assert type(Dimensions.a) is property, "a - не является объектом свойством property" + assert type(Dimensions.b) is property, "b - не является объектом свойством property" + assert type(Dimensions.c) is property, "c - не является объектом свойством property" + + # проверка что в объекте класса существуют 3 приватных локальных атрибута + assert ( + "_Dimensions__a" in x.__dict__ + and "_Dimensions__b" in x.__dict__ + and "_Dimensions__c" in x.__dict__ + ), "атрибуты не являются приватными" + # проверка что данные считываются с приватных атрибутов + assert ( + x.a == 10.0 and x.b == 20 and x.c == 30 + ), "при обращении к приватным атрибутам значения не получены проверьте объекты свойства" + # проверка что значения являются целым или вещественным числами + assert ( + type(x.a) in (int, float) + and type(x.b) in (int, float) + and type(x.c) in (int, float) + ), "значения должны быть или целым числом или вещественным" + # проверка на существование атрибутов минимум-максимум + assert hasattr(x, "MIN_DIMENSION"), "не найден атрибут MIN_DIMENSION" + assert hasattr(x, "MAX_DIMENSION"), "не найден атрибут MAX_DIMENSION" + + # проверка что значение в диапазоне + x.a = 9 + assert ( + x.a == 10.0 + ), "присваиваемое значение должно быть в диапазоне [MIN_DIMENSION; MAX_DIMENSION]" + x.b = -1 + assert ( + x.b == 20 + ), "присваиваемое значение должно быть в диапазоне [MIN_DIMENSION; MAX_DIMENSION]" + x.c = 1001 + assert ( + x.c == 30 + ), "присваиваемое значение должно быть в диапазоне [MIN_DIMENSION; MAX_DIMENSION]" + + # проверка + # С помощью магических методов данного занятия запретить создание локальных атрибутов MIN_DIMENSION и MAX_DIMENSION в объектах класса Dimensions. + # При попытке это сделать генерировать исключение: + # raise AttributeError("Менять атрибуты MIN_DIMENSION и MAX_DIMENSION запрещено.") + try: + x.MIN_DIMENSION = 0 + except AttributeError: + assert True + else: + assert False, "не сгенерировалось исключение AttributeError" + + try: + x.MAX_DIMENSION = 0 + except AttributeError: + assert True + else: + assert False, "не сгенерировалось исключение AttributeError" + + assert ( + "MIN_DIMENSION" not in x.__dict__ + ), "запретить создание локальных атрибутов MIN_DIMENSION и MAX_DIMENSION в объектах класса Dimensions" + assert ( + "MAX_DIMENSION" not in x.__dict__ + ), "запретить создание локальных атрибутов MIN_DIMENSION и MAX_DIMENSION в объектах класса Dimensions" + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + tests()