py_stepik/mod_oop/3.1_12_geyser.py
2024-04-10 16:50:32 +03:00

201 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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()