From 233a3e813408b45f980ba7def0217f398935ad4a Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 13 Apr 2024 15:54:27 +0300 Subject: [PATCH] +3.5_06 --- mod_oop/3.5_06_dimensions_shopitem.py | 186 ++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 mod_oop/3.5_06_dimensions_shopitem.py diff --git a/mod_oop/3.5_06_dimensions_shopitem.py b/mod_oop/3.5_06_dimensions_shopitem.py new file mode 100644 index 0000000..edc8e63 --- /dev/null +++ b/mod_oop/3.5_06_dimensions_shopitem.py @@ -0,0 +1,186 @@ +""" + https://stepik.org/lesson/701990/step/6?unit=702091 + +Объявите класс Dimensions (габариты) с атрибутами: +MIN_DIMENSION = 10 +MAX_DIMENSION = 10000 + +>>> Dimensions.MIN_DIMENSION, Dimensions.MAX_DIMENSION +(10, 10000) + +Каждый объект класса Dimensions должен создаваться командой: +d3 = Dimensions(a, b, c) # a, b, c - габаритные размеры +Значения a, b, c должны сохраняться в локальных приватных атрибутах __a, __b, __c объектах этого класса. +>>> d3 = Dimensions(10, 20, 30) +>>> d3._Dimensions__a, d3._Dimensions__b, d3._Dimensions__c +(10, 20, 30) + +Для изменения и доступа к приватным атрибутам в классе Dimensions должны быть объявлены объекты-свойства (property) с именами: a, b, c. +Причем, в момент присваивания нового значения должна выполняться проверка попадания числа в диапазон [MIN_DIMENSION; MAX_DIMENSION]. +Если число не попадает, то оно игнорируется и существующее значение не меняется. +>>> d3.a, d3.b, d3.c +(10, 20, 30) +>>> d3.a = 9; d3.a +10 + +С объектами класса Dimensions должны выполняться следующие операторы сравнения: +dim1 >= dim2 # True, если объем dim1 больше или равен объему dim2 +dim1 > dim2 # True, если объем dim1 больше объема dim2 +dim1 <= dim2 # True, если объем dim1 меньше или равен объему dim2 +dim1 < dim2 # True, если объем dim1 меньше объема dim2 +>>> dim1, dim2, dim3 = Dimensions(10, 20, 30), Dimensions(20, 15, 20), Dimensions(10, 15, 35) +>>> dim1 > dim3, dim1 == dim2, dim2 != dim3, dim3 < dim2, dim2 >= dim3 +(True, True, True, True, True) + +Объявите в программе еще один класс с именем ShopItem (товар), объекты которого создаются командой: +item = ShopItem(name, price, dim) +где name - название товара (строка); price - цена товара (целое или вещественное число); dim - габариты товара (объект класса Dimensions). +>>> item = ShopItem('Кеды', 1024, Dimensions(40, 30, 120)) + +В каждом объекте класса ShopItem должны создаваться локальные атрибуты: +name - название товара; +price - цена товара; +dim - габариты товара (объект класса Dimensions). +>>> item.name, item.price, item.dim +('Кеды', 1024, Dimensions(40, 30, 120)) + +Создайте список с именем lst_shop из четырех товаров со следующими данными: +- кеды; 1024; (40, 30, 120) +- зонт; 500.24; (10, 20, 50) +- холодильник; 40000; (2000, 600, 500) +- табуретка; 2000.99; (500, 200, 200) +>>> lst_shop[:2] +[ShopItem('кеды', 1024, Dimensions(40, 30, 120)), ShopItem('зонт', 500.24, Dimensions(10, 20, 50))] +>>> lst_shop[2:] +[ShopItem('холодильник', 40000, Dimensions(2000, 600, 500)), ShopItem('табуретка', 2000.99, Dimensions(500, 200, 200))] + +Сформируйте новый список lst_shop_sorted с упорядоченными по возрастанию объема (габаритов) товаров списка lst_shop, +используя стандартную функцию sorted() языка Python и ее параметр key для настройки сортировки. +Прежний список lst_shop должен оставаться без изменений. +>>> lst_shop_sorted[:2] +[ShopItem('зонт', 500.24, Dimensions(10, 20, 50)), ShopItem('кеды', 1024, Dimensions(40, 30, 120))] +>>> lst_shop_sorted[2:] +[ShopItem('табуретка', 2000.99, Dimensions(500, 200, 200)), ShopItem('холодильник', 40000, Dimensions(2000, 600, 500))] + +P.S. На экран в программе ничего выводить не нужно. +""" + +from functools import total_ordering + + +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 + + +@total_ordering +@make_properties(*"abc") +class Dimensions: + MIN_DIMENSION = 10 + MAX_DIMENSION = 10000 + + 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) + + @property + def volume(self): + return self.a * self.b * self.c + + def __len__(self): + return self.volume + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.volume == other.volume + return NotImplemented + + def __lt__(self, other): + if isinstance(other, self.__class__): + return self.volume < other.volume + return NotImplemented + + def __repr__(self): + return f"{self.__class__.__name__}{(self.a, self.b, self.c)!r}" + + +@total_ordering +class ShopItem: + def __init__(self, name, price, dim): + self.name, self.price, self.dim = name, price, dim + + def __repr__(self): + return f"{self.__class__.__name__}{(self.name, self.price, self.dim)!r}" + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.dim == other.dim + return NotImplemented + + def __lt__(self, other): + if isinstance(other, self.__class__): + return self.dim < other.dim + return NotImplemented + + +data = [ + ("кеды", 1024, (40, 30, 120)), + ("зонт", 500.24, (10, 20, 50)), + ("холодильник", 40000, (2000, 600, 500)), + ("табуретка", 2000.99, (500, 200, 200)), +] + +lst_shop = [ShopItem(name, price, Dimensions(*dim)) for name, price, dim in data] +lst_shop_sorted = sorted(lst_shop) + + +def tests(): + from base64 import b85decode + + b = ( + b"VRLh3a&#bUWo{^Jb97&GXm4;SAU!=GG%O$@(TC8u(Sgvr(7qtijnKQ$wa~oKwa~rMg3!LuvLMj1AZ&AVUvp@0a3IjV" + + b"(6u1ZfY7keve3QIz92Lr3JPpDb" + + b"0b7^mGb0{=0EFd#5EFdv5Fexc13T$(9UvqFSVQ_F|Ze%D^Xm4;ybY*QQC(yUhzRH83zPGBhk8L}_hhZgXjGZgV" + + b"IxFf1T4Ff1T7Fexc13T$(9UvqFSVQ_F|Ze%D^Xm4;ybY*QQC((t_zR^dAX_KUx6r=Oz0ravEFdS)y3n=Iw9$(vEFdS*" + + b"g3z$gvC)IkfY7zkg3!9quqP}aC((t_zRK5Fb97&GXm4;" + + b"|b8m8VWn^6nVRLh3a&#bUb97&Ga9?w8a&%>6AU!=Gb1Wbt(Sgvv(74fo(7w>RAZ&AVUvp@0a9?w8a&%>6Akl%*gwVdxfY7" + + b"|qxY2;nzRV?GC^RrEATuy5ATcs9DGFpVAUz;NX>Db0b7^mGb0" + + b"{=0EFd#5EFdv5FewUTGax-6L}_hhZgXjGZgVIzFf1T4Ff1T3Ffb_!VRLh3a&#bMF(5oWAY?KuAR^Gc(6!LA(6!Nk(7n*UA" + + b"keW(6!Nk(6G^h(7w@tAUr)H3So0|WpZ>NWHTTI(TdQu(7e#FAkl}=wb6jkwa~X9(7w>I(TdQu(7Mrr(Tgq7fzYzhzR