""" Урок 77. Практикум 19 — весь код примеров одним файлом. Источник: subjects/python-fundamentals/course/lessons/77-practice-19/examples.html Файл собран автоматически (tools/build_lesson_examples.py): правьте страницу урока. Запуск: python lesson-77.py """ # ==================================================================== # Пример 1. Базовый класс Door # ==================================================================== class Door: def __init__(self, code: str) -> None: self.__code = code def unlock(self, code: str) -> bool: if self.__is_valid_code(code): print("Access granted.") return True print("Access denied.") return False def __is_valid_code(self, code: str) -> bool: return code == self.__code door = Door("1234") door.unlock("0000") door.unlock("1234") # ==================================================================== # Пример 2. Смена кода # ==================================================================== class Door: def __init__(self, code: str) -> None: self.__code = code def unlock(self, code: str) -> bool: if self.__is_valid_code(code): print("Access granted.") return True print("Access denied.") return False def change_code(self, old_code: str, new_code: str) -> None: if not self.__is_valid_code(old_code): print("Access denied. Code not changed.") return self.__code = new_code print("Code changed.") def __is_valid_code(self, code: str) -> bool: return code == self.__code door = Door("1234") door.change_code("0000", "9999") door.unlock("1234") door.change_code("1234", "9999") door.unlock("1234") door.unlock("9999") # ==================================================================== # Пример 3. Блокировка после неудачных попыток # ==================================================================== import time from datetime import datetime, timedelta class Door: def __init__(self, code: str, max_attempts: int = 3, block_minutes: float = 15.0) -> None: self.__code = code self.__failed_attempts = 0 self.__max_attempts = max_attempts self.__block_duration = timedelta(minutes=block_minutes) self.__block_until = None def unlock(self, code: str) -> bool: if self.__is_blocked(): self.__show_block_time() return False if self.__is_valid_code(code): print("Access granted.") self.__reset_attempts() return True print("Access denied.") self.__handle_failed_attempt() return False def change_code(self, old_code: str, new_code: str) -> None: if self.__is_blocked(): self.__show_block_time() return if self.__is_valid_code(old_code): self.__code = new_code self.__reset_attempts() print("Code changed.") return print("Access denied. Code not changed.") self.__handle_failed_attempt() def __is_valid_code(self, code: str) -> bool: return code == self.__code def __is_blocked(self) -> bool: if self.__block_until is None: return False return datetime.now() < self.__block_until def __show_block_time(self) -> None: remaining = self.__block_until - datetime.now() seconds = int(remaining.total_seconds()) minutes, sec = divmod(seconds, 60) print(f"Door is blocked. Try again in {minutes} min {sec} sec.") def __check_block(self) -> None: if self.__failed_attempts >= self.__max_attempts: self.__block_until = datetime.now() + self.__block_duration print("Too many failed attempts. ", end="") self.__show_block_time() def __handle_failed_attempt(self) -> None: self.__failed_attempts += 1 self.__check_block() def __reset_attempts(self) -> None: self.__failed_attempts = 0 door = Door("1234", max_attempts=2, block_minutes=0.05) door.unlock("1111") door.change_code("2222", "9999") door.unlock("1234") time.sleep(5) door.unlock("1234") # ==================================================================== # Пример 4. Пользовательское исключение # ==================================================================== import time from datetime import datetime, timedelta class DoorBlockedError(Exception): '''Raised when trying to access a blocked door.''' pass class Door: def __init__(self, code: str, max_attempts: int = 3, block_minutes: float = 15.0) -> None: self.__code = code self.__failed_attempts = 0 self.__max_attempts = max_attempts self.__block_duration = timedelta(minutes=block_minutes) self.__block_until = None def unlock(self, code: str) -> bool: if self.__is_blocked(): raise DoorBlockedError(self.__remaining_block_time()) if self.__is_valid_code(code): print("Access granted.") self.__reset_attempts() return True print("Access denied.") self.__handle_failed_attempt() return False def change_code(self, old_code: str, new_code: str) -> None: if self.__is_blocked(): raise DoorBlockedError(self.__remaining_block_time()) if self.__is_valid_code(old_code): self.__code = new_code self.__reset_attempts() print("Code changed.") return print("Access denied. Code not changed.") self.__handle_failed_attempt() def __is_valid_code(self, code: str) -> bool: return code == self.__code def __is_blocked(self) -> bool: if self.__block_until is None: return False return datetime.now() < self.__block_until def __remaining_block_time(self) -> str: remaining = self.__block_until - datetime.now() seconds = int(remaining.total_seconds()) minutes, sec = divmod(seconds, 60) return f"Door is blocked. Try again in {minutes} min {sec} sec." def __check_block(self) -> None: if self.__failed_attempts >= self.__max_attempts: self.__block_until = datetime.now() + self.__block_duration print("Too many failed attempts.") def __handle_failed_attempt(self) -> None: self.__failed_attempts += 1 self.__check_block() def __reset_attempts(self) -> None: self.__failed_attempts = 0 door = Door("1234", max_attempts=2, block_minutes=0.05) try: door.unlock("1111") except DoorBlockedError as e: print(e) try: door.change_code("0000", "9999") except DoorBlockedError as e: print(e) try: door.unlock("1234") except DoorBlockedError as e: print(e) time.sleep(5) try: door.unlock("1234") except DoorBlockedError as e: print(e)