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