109 lines
3.3 KiB
Python
109 lines
3.3 KiB
Python
|
# 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()
|