# https://stepik.org/lesson/701985/step/11?unit=702086 from typing import Protocol class Validator(Protocol): def validate(self, value: str) -> bool: ... class ValidatedField: ValueValidator: Validator def __init__(self, *args, **kwargs): self.validator = self.ValueValidator(*args, **kwargs) def __set_name__(self, owner, name): self.name = "_" + name def __get__(self, instance, owner): return getattr(instance, self.name) def __set__(self, instance, value): if self.validator.validate(value): setattr(instance, self.name, value) class StringValue(ValidatedField): class ValueValidator(Validator): def __init__(self, min_length, max_length): self.min_length, self.max_length = min_length, max_length def validate(self, value: str) -> bool: return ( isinstance(value, str) and self.min_length <= len(value) <= self.max_length ) class PriceValue(ValidatedField): class ValueValidator(Validator): def __init__(self, max_value): self.max_value = max_value def validate(self, value: str) -> bool: return isinstance(value, int) and 0 <= value <= self.max_value class Product: name = StringValue(min_length=2, max_length=50) price = PriceValue(max_value=10000) def __init__(self, name, price): self.name = name self.price = price class SuperShop: def __init__(self, name): self.name = name self.goods: list[Product] = [] def add_product(self, product: Product): self.goods.append(product) def remove_product(self, product: Product): self.goods.remove(product) shop = SuperShop("У Балакирева") shop.add_product(Product("Курс по Python", 0)) shop.add_product(Product("Курс по Python ООП", 2000)) for p in shop.goods: print(f"{p.name}: {p.price}") def tests(): shop = SuperShop("У Балакирева") shop.add_product(Product("name", 100)) shop.add_product(Product("name", 100)) assert ( shop.name == "У Балакирева" ), "атрибут name объекта класса SuperShop содержит некорректное значение" for p in shop.goods: assert p.price == 100, "дескриптор price вернул неверное значение" assert p.name == "name", "дескриптор name вернул неверное значение" t = Product("name 123", 1000) shop.add_product(t) shop.remove_product(t) assert ( len(shop.goods) == 2 ), "неверное количество товаров: возможно некорректно работают методы add_product и remove_product" assert hasattr(shop.goods[0], "name") and hasattr(shop.goods[0], "price") t = Product(1000, "name 123") if hasattr(t, "_name"): assert type(t.name) == str, "типы поля name должнен быть str" if hasattr(t, "_price"): assert type(t.price) in ( int, float, ), "тип поля price должнен быть int или float" tests()