📋 Формулировка задания
Для этого практического урока нет отдельного задания в LMS, поэтому домашним заданием становятся сами пять задач урока:
- Сумма чисел списка — рекурсивная функция с валидацией типов.
- Реверс строки — рекурсивная функция с проверкой строкового типа.
- Глубина вложенности списка — рекурсивный подсчёт глубины.
- Сумма продаж — рекурсивный обход дерева подразделений.
- Читабельный формат словаря — рекурсивное «выпрямление» вложенного словаря.
🔧 Шаг 0. Подготовка окружения
Эти шаги одинаковы для всех уроков курса.
Создайте рабочую папку
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
echo "*.log" >> .gitignore
git add README.md .gitignore
git commit -m "init: базовая структура репозитория"
Создайте папку для урока и виртуальное окружение
mkdir lesson-49
cd lesson-49
python -m venv venv
# Windows
venv\Scripts\activate
# Mac / Linux
source venv/bin/activate
Создайте ветку для задания
cd ..
git checkout -b lesson/49-practice-12
🛠️ Шаги выполнения задания
Шаг 1: создайте файл homework_49.py
В папке lesson-49 создайте файл и реализуйте пять функций.
Шаг 2: добавьте валидацию через isinstance
Перед рекурсивной обработкой проверяйте тип аргумента. При ошибке возбуждайте TypeError с понятным сообщением.
Шаг 3: обработайте исключения при вызове
Каждый вызов функции в блоке if __name__ == "__main__": оберните в try/except, чтобы программа не прерывалась.
✅ Полное решение
Ниже приведён готовый файл. Совет: попробуйте выполнить задание самостоятельно, прежде чем копировать ответ.
"""Lesson 49 practice: recursion + validation with exceptions."""
def recursive_sum(numbers: list) -> float:
"""Return the sum of all numbers in a list recursively."""
if not isinstance(numbers, list):
raise TypeError("Argument must be a list")
if not numbers:
return 0
head = numbers[0]
if not isinstance(head, (int, float)):
raise TypeError(f"All elements must be numbers, got {type(head).__name__}")
return head + recursive_sum(numbers[1:])
def reverse_string(text: str) -> str:
"""Return the reversed string using recursion."""
if not isinstance(text, str):
raise TypeError("Argument must be a string")
if len(text) <= 1:
return text
return text[-1] + reverse_string(text[:-1])
def list_depth(nested_list: list) -> int:
"""Return the maximum nesting depth of a list."""
if not isinstance(nested_list, list):
raise TypeError("Argument must be a list")
max_inner = 0
for item in nested_list:
if isinstance(item, list):
max_inner = max(max_inner, list_depth(item))
return 1 + max_inner
def total_sales(department: dict) -> int | float:
"""Return the total sales of a department and all its sub-departments."""
if not isinstance(department, dict):
raise TypeError("Department must be a dict")
sales = department.get("sales", 0)
total = sales
sub_departments = department.get("sub_departments")
if sub_departments is not None:
if not isinstance(sub_departments, list):
raise TypeError("sub_departments must be a list")
for sub in sub_departments:
if not isinstance(sub, dict):
raise TypeError("Each sub_department must be a dict")
total += total_sales(sub)
return total
def flatten_dict(data: dict, prefix: str = "") -> dict:
"""Convert a nested dict into a flat dict with dot-separated keys."""
if not isinstance(data, dict):
raise TypeError("Argument must be a dict")
result = {}
for key, value in data.items():
full_key = f"{prefix}.{key}" if prefix else key
if isinstance(value, dict):
result.update(flatten_dict(value, full_key))
else:
result[full_key] = value
return result
if __name__ == "__main__":
# Task 1
numbers = [1, 2, 3, 4, 5]
try:
print(recursive_sum(numbers))
except (TypeError, ValueError) as e:
print(f"Task 1 error: {e}")
# Task 2
text = "recursion"
try:
print(reverse_string(text))
except TypeError as e:
print(f"Task 2 error: {e}")
# Task 3
nested_list = [1, [2, [3, [4, [5]]]], 6, [[7, 8], 9]]
try:
print("Максимальная глубина:", list_depth(nested_list))
except TypeError as e:
print(f"Task 3 error: {e}")
# Task 4
company_structure = {
"dept_name": "Head Office",
"sales": 100,
"sub_departments": [
{
"dept_name": "Sales Department",
"sales": 200,
"sub_departments": [
{"dept_name": "B2B Sales", "sales": 120}
]
},
{
"dept_name": "IT Department",
"sales": 150,
"sub_departments": [
{
"dept_name": "DevOps",
"sales": 300,
"sub_departments": [
{"dept_name": "Cloud Infrastructure", "sales": 180}
]
},
{"dept_name": "QA Department", "sales": 90}
]
}
]
}
try:
print("Общая сумма продаж:", total_sales(company_structure))
except TypeError as e:
print(f"Task 4 error: {e}")
# Task 5
data = {
"user": {
"id": 123,
"info": {
"name": "Alice",
"location": {
"city": "Berlin",
"coordinates": {"lat": 52.52, "lon": 13.405}
},
"hobby": ["swimming", "drawing"]
}
},
"score": 95
}
flat = flatten_dict(data)
print("Данные для анализа:")
for key, value in flat.items():
print(f"{key} : {value}")
🧪 Как проверить решение
- Активируйте venv:
venv\Scripts\activate(Windows) илиsource venv/bin/activate(Mac/Linux). - Запустите файл:
python homework_49.py. - Проверьте вывод:
15noisrucerМаксимальная глубина: 5Общая сумма продаж: 1140- Плоский словарь с ключами
user.id,scoreи т.д.
🐛 Отладка в VS Code
Если что-то не работает:
- Поставьте точку останова на строке с базовым случаем рекурсии.
- Нажмите F5 или выберите «Run → Start Debugging».
- На панели Debug следите за стеком вызовов и значениями аргументов.
- Проверьте, что все функции возвращают значения в базовых случаях.
💾 Сохранение работы
git add lesson-49/
git commit -m "lesson-49: recursion and exception validation"
git push
💡 Советы и типичные ошибки
- Не забывайте базовый случай рекурсии.
- Проверяйте тип через
isinstance, а неtype(). - Не используйте «голый»
except:— указывайте конкретные исключения. - Проверяйте аргументы в начале функции, а не внутри рекурсивного шага.