From c20c79ab47344d3a3d0920eabbcfe86ef6b7c4b1 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 10 Apr 2024 16:50:32 +0300 Subject: [PATCH] + 3.1_12 --- mod_oop/3.1_12_geyser.py | 200 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 mod_oop/3.1_12_geyser.py diff --git a/mod_oop/3.1_12_geyser.py b/mod_oop/3.1_12_geyser.py new file mode 100644 index 0000000..9def8ca --- /dev/null +++ b/mod_oop/3.1_12_geyser.py @@ -0,0 +1,200 @@ +""" + 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()