AssertionError: когда и как применять assert в Python

Раздел: Основы Python -> Распространенные исключения 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

AssertionError в Python - comments

En
Assertion error python (python)