AssertionError: когда и как применять assert в Python
AssertionError в Python: основы и применение
Исключение AssertionError возникает при выполнении инструкции assert, когда проверяемое условие оказывается ложным. Это встроенный механизм отладки, позволяющий верифицировать инварианты кода.
Основное решение: использование assert с сообщением об ошибке
Как сделать проверку предусловий с информативным сообщением?
def divide(a, b):
assert b != 0, "Делитель не может быть нулевым"
return a / b
divide(10, 0)Assertion error python (assertionerror в python)
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in divide AssertionError: Делитель не может быть нулевым
Здесь assert проверяет, что b не равно нулю. Если условие нарушено – поднимается AssertionError с заданным сообщением. Такой подход удобен при разработке и тестировании.
Типичная проблема: утверждения assert могут быть глобально отключены при запуске Python с флагом -O (optimize). В таком случае assert не будет выполняться, и проверка будет пропущена. Это делает assert непригодным для валидации пользовательского ввода или критичных проверок в продакшне.
Вариант 1: перехват AssertionError с помощью try/except
Как отловить AssertionError и выполнить альтернативное действие?
try:
x = int(input("Введите положительное число: "))
assert x > 0, "Число должно быть положительным"
print(f"Квадрат числа: {x**2}")
except AssertionError as e:
print(f"Ошибка: {e}")
Пример перехватывает исключение и выводит сообщение. Однако если assert отключен (флаг -O), то условие не будет проверено, и код продолжит работу с некорректными данными.
Проблема: если assert отключён, try/except не поможет. Решение – использовать явную проверку if и raise ValueError вместо assert.
Вариант 2: отключение проверок assert с помощью флага -O
Как отключить все assert в коде для повышения производительности?
# файл test.py
def check(x):
assert x > 0, "Недопустимое значение"
return x * 2
print(check(5))
print(check(-1))
Запуск без оптимизации: python test.py приведёт к AssertionError на втором вызове. Запуск с флагом python -O test.py пропустит assert, и функция вернёт -2, что может быть неверным.
# вывод при -O: 10 -2
Проблема: отключение assert скрывает ошибки, но не исправляет их. Используйте флаг -O только после тщательного тестирования.
Вариант 3: использование assert в юнит-тестах
Как применять assert для написания автоматических тестов?
def test_addition():
assert 1 + 1 == 2, "Сложение неверно"
assert 0 + 0 == 0
print("Тест пройден")
test_addition()
Юнит-тесты часто используют assert для проверки ожидаемых результатов. При ошибке поднимается AssertionError, и тест считается проваленным. Библиотеки вроде pytest предоставляют расширенный вывод.
Проблема: если тестовая среда запускает код с флагом -O, тесты перестанут обнаруживать ошибки. Поэтому в тестах рекомендуется использовать специальные функции-ассерты из фреймворков (например, pytest.raises), а не встроенный assert.
Расширенные примеры работы с AssertionError
Пример 1: assert с логическим выражением и несколькими условиями
def validate_age(age):
assert isinstance(age, int) and 0 <= age <= 150, (
f"Некорректный возраст: {age}"
)
return f"Возраст {age} лет"
print(validate_age(25))
# print(validate_age(-5)) # раскомментировать для проверки
Возраст 25 лет
Пример 2: assert внутри метода класса и проверка состояния объекта
class BankAccount:
def __init__(self, balance):
self.balance = balance
def withdraw(self, amount):
assert amount > 0, "Сумма снятия должна быть положительной"
assert self.balance >= amount, "Недостаточно средств"
self.balance -= amount
return self.balance
acc = BankAccount(100)
acc.withdraw(30)
print(acc.balance) # 70
# acc.withdraw(-10) # AssertionError: Сумма снятия должна быть положительной
70
Пример 3: assert с использованием __debug__ для условной проверки
DEBUG = __debug__ # True, если не задан флаг -O
def process(data):
if DEBUG:
assert len(data) > 0, "Данные не должны быть пустыми"
# обработка...
return data
print(process([1, 2]))
print(process([])) # AssertionError при обычном запуске, пропуск при -O
[1, 2] Traceback (most recent call last): ... AssertionError: Данные не должны быть пустыми
Пример 4: assert в комбинации with raise и собственное исключение
class ValidationError(Exception):
pass
def set_age(age):
if not (0 <= age <= 150):
raise ValidationError(f"Недопустимый возраст: {age}")
assert isinstance(age, int), "Возраст должен быть целым числом"
return age
try:
set_age(200)
except ValidationError as ve:
print(f"Поймано ValidationError: {ve}")
except AssertionError as ae:
print(f"Поймано AssertionError: {ae}")
Поймано ValidationError: Недопустимый возраст: 200
Пример 5: assert с сообщением, содержащим форматирование
def connect(host, port):
assert 1 <= port <= 65535, (
f"Порт {port} вне допустимого диапазона"
)
assert isinstance(host, str) and len(host) > 0, (
f"Некорректный хост: {host}"
)
return f"Подключение к {host}:{port}"
print(connect("localhost", 8080))
# print(connect("", 80)) # AssertionError с сообщением
Подключение к localhost:8080