201 lines
8.3 KiB
Python
201 lines
8.3 KiB
Python
|
"""
|
|||
|
https://stepik.org/lesson/701986/step/12?unit=702087
|
|||
|
|
|||
|
Объявите класс GeyserClassic - фильтр для очистки воды. В этом классе должно быть три слота для фильтров. Каждый слот строго для своего класса фильтра:
|
|||
|
|
|||
|
Mechanical - для очистки от крупных механических частиц;
|
|||
|
Aragon - для последующей очистки воды;
|
|||
|
Calcium - для обработки воды на третьем этапе.
|
|||
|
|
|||
|
|
|||
|
Объекты классов фильтров должны создаваться командами:
|
|||
|
filter_1 = Mechanical(дата установки)
|
|||
|
filter_2 = Aragon(дата установки)
|
|||
|
filter_3 = Calcium(дата установки)
|
|||
|
|
|||
|
Во всех объектах этих классов должен формироваться локальный атрибут:
|
|||
|
date - дата установки фильтров (для простоты - положительное вещественное число).
|
|||
|
|
|||
|
Также нужно запретить изменение этого атрибута после создания объектов этих классов (только чтение). В случае присвоения нового значения, прежнее значение не менять. Ошибок никаких не генерировать.
|
|||
|
|
|||
|
Объекты класса GeyserClassic должны создаваться командой:
|
|||
|
>>> g = GeyserClassic()
|
|||
|
|
|||
|
А сам класс иметь атрибут:
|
|||
|
MAX_DATE_FILTER = 100 - максимальное время работы фильтра (любого)
|
|||
|
>>> GeyserClassic.MAX_DATE_FILTER
|
|||
|
100
|
|||
|
|
|||
|
и следующие методы:
|
|||
|
add_filter(self, slot_num, filter) - добавление фильтра filter в указанный слот slot_num (номер слота: 1, 2 и 3), если он (слот) пустой (без фильтра). Также здесь следует проверять, что в первый слот можно установить только объекты класса Mechanical, во второй - объекты класса Aragon и в третий - объекты класса Calcium. Иначе слот должен оставаться пустым.
|
|||
|
remove_filter(self, slot_num) - извлечение фильтра из указанного слота (slot_num: 1, 2, и 3);
|
|||
|
get_filters(self) - возвращает кортеж из набора трех фильтров в порядке их установки (по возрастанию номеров слотов);
|
|||
|
water_on(self) - включение воды: возвращает True, если вода течет и False - в противном случае.
|
|||
|
|
|||
|
>>> {a in b for b in (dir(GeyserClassic),) for a in "add_filter remove_filter get_filters water_on".split()}
|
|||
|
{True}
|
|||
|
|
|||
|
Метод water_on() должен возвращать значение True при выполнении следующих условий:
|
|||
|
- все три фильтра установлены в слотах;
|
|||
|
- все фильтры работают в пределах срока службы (значение (time.time() - date) должно быть в пределах [0; MAX_DATE_FILTER])
|
|||
|
|
|||
|
Пример использования классов (эти строчки в программе писать не нужно):
|
|||
|
my_water = GeyserClassic()
|
|||
|
my_water.add_filter(1, Mechanical(time.time()))
|
|||
|
my_water.add_filter(2, Aragon(time.time()))
|
|||
|
w = my_water.water_on() # False
|
|||
|
my_water.add_filter(3, Calcium(time.time()))
|
|||
|
w = my_water.water_on() # True
|
|||
|
f1, f2, f3 = my_water.get_filters() # f1, f2, f3 - ссылки на соответствующие объекты классов фильтров
|
|||
|
my_water.add_filter(3, Calcium(time.time())) # повторное добавление в занятый слот невозможно
|
|||
|
my_water.add_filter(2, Calcium(time.time())) # добавление в "чужой" слот также невозможно
|
|||
|
|
|||
|
>>> import time
|
|||
|
>>> my_water = GeyserClassic()
|
|||
|
>>> my_water.add_filter(1, Mechanical(time.time()))
|
|||
|
>>> my_water.add_filter(2, Aragon(time.time()))
|
|||
|
>>> my_water.water_on()
|
|||
|
False
|
|||
|
>>> my_water.add_filter(3, Calcium(time.time()))
|
|||
|
>>> my_water.water_on()
|
|||
|
True
|
|||
|
>>> a, b, c = my_water.get_filters()
|
|||
|
>>> my_water.add_filter(3, Calcium(time.time()))
|
|||
|
>>> my_water.get_filters() == (a, b, c)
|
|||
|
True
|
|||
|
>>> my_water = GeyserClassic()
|
|||
|
>>> my_water.add_filter(2, Calcium(time.time()))
|
|||
|
>>> my_water.get_filters() == (None, None, None)
|
|||
|
True
|
|||
|
|
|||
|
P.S. На экран ничего выводить не нужно.
|
|||
|
"""
|
|||
|
|
|||
|
import time
|
|||
|
|
|||
|
|
|||
|
class Filter:
|
|||
|
slot: int
|
|||
|
|
|||
|
def __init__(self, date: float):
|
|||
|
self.__date = date
|
|||
|
|
|||
|
def __init_subclass__(cls, *args, **kwargs):
|
|||
|
if "slot" in kwargs:
|
|||
|
cls.slot = kwargs["slot"]
|
|||
|
|
|||
|
@property
|
|||
|
def date(self):
|
|||
|
return self.__date
|
|||
|
|
|||
|
def __setattr__(self, name: str, value):
|
|||
|
if name in ("slot", "date"):
|
|||
|
return
|
|||
|
super().__setattr__(name, value)
|
|||
|
|
|||
|
|
|||
|
class Mechanical(Filter, slot=1):
|
|||
|
...
|
|||
|
|
|||
|
|
|||
|
class Aragon(Filter, slot=2):
|
|||
|
...
|
|||
|
|
|||
|
|
|||
|
class Calcium(Filter, slot=3):
|
|||
|
...
|
|||
|
|
|||
|
|
|||
|
class GeyserClassic:
|
|||
|
MAX_DATE_FILTER = 100
|
|||
|
|
|||
|
def __init__(self):
|
|||
|
self.__filters = [None, None, None]
|
|||
|
|
|||
|
def __setattr__(self, name: str, value):
|
|||
|
if name == "MAX_DATE_FILTER":
|
|||
|
return
|
|||
|
super().__setattr__(name, value)
|
|||
|
|
|||
|
def add_filter(self, slot_num: int, flt: Filter):
|
|||
|
if self.__filters[slot_num - 1] or slot_num != flt.slot:
|
|||
|
return
|
|||
|
self.__filters[slot_num - 1] = flt
|
|||
|
|
|||
|
def remove_filter(self, slot_num: int):
|
|||
|
self.__filters[slot_num - 1] = None
|
|||
|
|
|||
|
def get_filters(self) -> tuple:
|
|||
|
return tuple(self.__filters)
|
|||
|
|
|||
|
def water_on(self) -> bool:
|
|||
|
date = time.time()
|
|||
|
for flt in self.__filters:
|
|||
|
if not flt:
|
|||
|
return False
|
|||
|
if not 0 <= (date - flt.date) <= self.MAX_DATE_FILTER:
|
|||
|
return False
|
|||
|
return True
|
|||
|
|
|||
|
|
|||
|
def tests():
|
|||
|
my_water = GeyserClassic()
|
|||
|
my_water.add_filter(1, Mechanical(time.time()))
|
|||
|
my_water.add_filter(2, Aragon(time.time()))
|
|||
|
|
|||
|
assert (
|
|||
|
my_water.water_on() == False
|
|||
|
), "метод water_on вернул True, хотя не все фильтры были установлены"
|
|||
|
|
|||
|
my_water.add_filter(3, Calcium(time.time()))
|
|||
|
assert (
|
|||
|
my_water.water_on()
|
|||
|
), "метод water_on вернул False при всех трех установленных фильтрах"
|
|||
|
|
|||
|
f1, f2, f3 = my_water.get_filters()
|
|||
|
assert (
|
|||
|
isinstance(f1, Mechanical)
|
|||
|
and isinstance(f2, Aragon)
|
|||
|
and isinstance(f3, Calcium)
|
|||
|
), "фильтры должны быть устанлены в порядке: Mechanical, Aragon, Calcium"
|
|||
|
|
|||
|
my_water.remove_filter(1)
|
|||
|
assert (
|
|||
|
my_water.water_on() == False
|
|||
|
), "метод water_on вернул True, хотя один из фильтров был удален"
|
|||
|
|
|||
|
my_water.add_filter(1, Mechanical(time.time()))
|
|||
|
assert (
|
|||
|
my_water.water_on()
|
|||
|
), "метод water_on вернул False, хотя все три фильтра установлены"
|
|||
|
|
|||
|
f1, f2, f3 = my_water.get_filters()
|
|||
|
my_water.remove_filter(1)
|
|||
|
|
|||
|
my_water.add_filter(1, Mechanical(time.time() - GeyserClassic.MAX_DATE_FILTER - 1))
|
|||
|
assert (
|
|||
|
my_water.water_on() == False
|
|||
|
), "метод water_on вернул True, хотя у одного фильтра истек срок его работы"
|
|||
|
|
|||
|
f1 = Mechanical(1.0)
|
|||
|
f2 = Aragon(2.0)
|
|||
|
f3 = Calcium(3.0)
|
|||
|
assert (
|
|||
|
0.9 < f1.date < 1.1 and 1.9 < f2.date < 2.1 and 2.9 < f3.date < 3.1
|
|||
|
), "неверное значение атрибута date в объектах фильтров"
|
|||
|
|
|||
|
f1.date = 5.0
|
|||
|
f2.date = 5.0
|
|||
|
f3.date = 5.0
|
|||
|
|
|||
|
assert (
|
|||
|
0.9 < f1.date < 1.1 and 1.9 < f2.date < 2.1 and 2.9 < f3.date < 3.1
|
|||
|
), "локальный атрибут date в объектах фильтров должен быть защищен от изменения"
|
|||
|
|
|||
|
|
|||
|
if __name__ == "__main__":
|
|||
|
import doctest
|
|||
|
|
|||
|
doctest.testmod()
|
|||
|
tests()
|