📋 Формулировка задания
Исходное задание из LMS:
Электронная дверь с кодом
- Класс Door. Создайте класс
Door, представляющий электронную дверь. При создании передаётся первоначальный код доступа. Есть методunlock(code), который разрешает доступ при правильном коде и отклоняет при неверном. Продумайте, какие поля и методы следует скрыть от внешнего доступа, а какие оставить открытыми. - Смена кода. Доработайте класс
Door. Добавьте метод для смены кода. Новый код можно установить только после проверки текущего кода. Логика проверки корректности кода не должна дублироваться. - Блокировка двери. Доработайте класс
Door. При создании можно указать максимальное количество попыток (по умолчанию 3) и время блокировки в минутах (по умолчанию 15). Если попытки исчерпаны, дверь блокируется на указанное время. Пока дверь заблокирована — сменить код или открыть нельзя. Неверные попытки входа или смены кода учитываются общим счётчиком. При блокировке должно выводиться сообщение с указанием оставшегося времени ожидания. - Исключение при блокировке. Доработайте класс
Door. Создайте пользовательское исключениеDoorBlockedError. При попытке открыть дверь или сменить код во время блокировки выбрасывайте это исключение вместо вывода сообщения. Обработайте исключение в коде вызова.
🔧 Шаг 0. Подготовка окружения
Перед началом работы над любым заданием курса нужно настроить окружение. Эти шаги одинаковы для всех уроков.
.gitignore, единая история, легко переключаться между уроками.
Создайте (или откройте) рабочую папку
В VS Code нажмите Ctrl+K Ctrl+O → выберите или создайте папку python-fundamentals-practice. Это будет корень вашего учебного репозитория.
# Или в терминале VS Code (Ctrl + `):
mkdir python-fundamentals-practice
cd python-fundamentals-practice
Инициализируйте Git-репозиторий (один раз)
git init
echo "# Python Fundamentals — Практические работы" > README.md
echo "venv/" > .gitignore
echo "__pycache__/" >> .gitignore
echo "*.pyc" >> .gitignore
echo ".env" >> .gitignore
git add README.md .gitignore
git commit -m "init: базовая структура репозитория"
Создайте папку для текущего урока
mkdir -p lesson-77
cd lesson-77
Создайте виртуальное окружение (venv)
# Windows
python -m venv venv
venv\Scripts\activate
# Mac / Linux
python3 -m venv venv
source venv/bin/activate
После активации в начале строки терминала появится (venv).
Создайте ветку для задания
cd ..
git checkout -b lesson/77-door-code
Именование веток: lesson/XX-краткое-название.
🛠️ Шаги выполнения задания
Теперь, когда окружение готово, приступайте к решению.
Создайте файл door.py
В папке lesson-77 создайте файл door.py.
Реализуйте класс Door поэтапно
Сначала сделайте базовый unlock, затем change_code, затем блокировку и, наконец, DoorBlockedError. Запускайте файл после каждого этапа, чтобы убедиться, что всё работает.
Проверьте работу в VS Code
# В терминале с активированным venv
python lesson-77/door.py
Ожидаемый вывод (примерный):
Access denied.
Access denied. Code not changed.
Too many failed attempts.
Door is blocked. Try again in 0 min 1 sec.
Access granted.
✅ Полное решение
Ниже приведено полное решение задания. Совет: попробуйте выполнить самостоятельно, прежде чем смотреть ответ.
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
if __name__ == "__main__":
door = Door("1234", max_attempts=2, block_minutes=0.03)
attempts = [
lambda: door.unlock("1111"),
lambda: door.change_code("0000", "9999"),
lambda: door.unlock("1234"),
]
for action in attempts:
try:
action()
except DoorBlockedError as e:
print(e)
time.sleep(2)
try:
door.unlock("1234")
except DoorBlockedError as e:
print(e)
🧪 Как проверить решение
- Активируйте venv:
venv\Scripts\activate(Windows) илиsource venv/bin/activate(Mac/Linux). - Запустите файл:
python lesson-77/door.py. - Проверьте вывод в терминале — не должно быть ошибок.
- Убедитесь, что после двух неудач дверь блокируется, а через 2 секунды открывается правильным кодом.
🐛 Отладка в VS Code
Если что-то не работает:
- Поставьте точку останова (breakpoint) кликом слева от номера строки, например на строке
if self.__is_blocked():. - Нажмите F5 или выберите «Run → Start Debugging».
- Используйте панель Debug: проверьте значения
__failed_attemptsи__block_until. - Посмотрите Terminal — Python покажет номер строки с ошибкой и traceback.
💾 Сохранение работы
git add lesson-77/
git commit -m "lesson-77: электронная дверь с кодом и пользовательским исключением"
git push
💡 Советы и типичные ошибки
- Не забудьте сбросить
__failed_attemptsпосле успешногоunlockилиchange_code. - Проверяйте блокировку в начале каждого публичного метода — это guard clause.
- Используйте
datetimeиtimedelta, а не «сырые» секунды. - Не коммитьте папку
venv/— она указана в.gitignore.