📜 Как может выглядеть «плоский» подход
Без явной валидации функция может получить неожиданные данные и упасть позже, на внутренней операции. Пример с type() вместо isinstance:
# Naive approach from the source style
def recursive_sum(numbers):
if type(numbers) != list: # less flexible than isinstance
print("Ошибка: аргумент должен быть списком")
return None
if not numbers:
return 0
return numbers[0] + recursive_sum(numbers[1:])
print(recursive_sum([1, 2, "x", 4])) # crashes at runtime, no element check
Этот код работает только для списков верхнего уровня, не проверяет элементы и не возбуждает исключение — он просто возвращает None.
❌ Что можно улучшить
type(x) == listне поддерживает наследование и выглядит неидиоматично.- Вывод ошибки через
printи возвратNoneскрывают причину проблемы от вызывающего кода. - Нет проверки элементов: строка или словарь внутри списка сломают рекурсию на позднем этапе.
- Нет type hints — сложнее понять, какие типы ожидает функция.
✅ Современный вариант
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:])
numbers = [1, 2, 3, 4, 5]
try:
print(recursive_sum(numbers))
except (TypeError, ValueError) as e:
print(f"Ошибка: {e}")
Что улучшилось:
- Guard clause с
isinstanceв начале функции. - Конкретное исключение
TypeErrorвместоNoneили общегоException. - Проверка каждого элемента перед сложением.
- Type hints делают сигнатуру функции понятной.
- f-string формирует понятное сообщение об ошибке.
Рекомендуемый стиль обработки ошибок
try:
print(reverse_string(123))
except TypeError as e:
print(f"Ошибка: {e}")
Ловим только тот тип исключения, который может возникнуть, и сообщаем пользователю понятный текст.
🕰️ Когда старый подход ещё можно встретить
Учебные и быстрые скрипты часто используют print и простые проверки. Это нормально для демонстрации, но в домашних заданиях и реальных проектах стоит применять isinstance, guard clauses и конкретные исключения.
type() и рекомендации по isinstance выходят за рамки исходного материала; актуальные рекомендации всегда стоит сверять с официальной документацией Python.