UpPetto

This is a real course generated by UpPetto — unedited.

AI-generated. Two models wrote it, a third checked every risky claim against sources, a fourth re-checked.

Create my own course

Динамическая типизация runtime: какие ошибки C-компилятор ловил, а Python не ловит

core перечислить, какие классы ошибок в вашем C-коде компилятор ловил бесплатно, и понять, что их нужно закрывать иначе в Python

В C граница между «код не собрался» и «код упал в проде» — это граница между компилятором и вами. Компилятор ловит несовпадение типов аргументов, вызов функции с неверным числом параметров, присваивание указателя несовместимого типа, обращение к полю структуры, которого не существует. Вы получаете эти проверки бесплатно, на каждой строке, независимо от того, выполнялась ли она хоть раз.

В Python этой стадии нет. Есть только один режим проверки — исполнение конкретной строки с конкретными данными. Если строка x + y никогда не выполнилась с y, которое не поддерживает сложение, интерпретатор никогда не узнает, что там ошибка. Это меняет саму природу «правильности» кода: в C корректность частично гарантирует компилятор до запуска, в Python корректность типов — функция от покрытия кода тестами и реальными входными данными.

Причина — в объектной модели. В Python тип принадлежит объекту, а имя — это лишь привязка к объекту; одно и то же имя может ссылаться сначала на int, потом на str. Интерпретатор не может знать заранее, какой объект придёт в функцию, поэтому проверяет операции «по факту».

Категория C Python
Несовпадение типа аргумента ошибка компиляции TypeError в момент вызова
Опечатка в имени переменной/поля ошибка компиляции NameError/AttributeError в момент обращения
Неверное число аргументов функции ошибка компиляции TypeError в момент вызова
Несовместимая операция (x + структура) ошибка компиляции TypeError при выполнении операции
graph TD
    A["Код .c"] --> B{"Компилятор gcc/clang"}
    B -->|"проверка типов пройдена"| C["Исполняемый файл"]
    B -->|"ошибка типа"| D["Остановка сборки"]
    C --> E["Запуск"]
    F["Код .py"] --> G["Интерпретатор python"]
    G --> H["Выполнение строки за строкой"]
    H -->|"встречена операция с несовместимым типом"| I["Runtime-исключение TypeError"]
    H -->|"все выполненные операции корректны"| J["Успешное завершение"]
жизненный цикл ошибки типа в C (до запуска) и в Python (во время выполнения)

Ключевое отличие не в том, что Python «менее безопасен», а в том, что проверка сдвинута с этапа «до запуска» на этап «во время исполнения конкретной ветки». Если у вас есть код, который срабатывает раз в год при определённом входе, компилятор C проверил бы его типы всё равно. Python проверит их только тогда, когда этот код реально выполнится. Отсюда два следствия: юнит-тесты становятся не роскошью, а заменой части работы компилятора, а часть контроля переносится на внешние инструменты статического анализа (урок 3).

Разобранный пример

Практический перенос C-функции в Python «построчно»:

def clamp(value, low, high):
    if value < low:
        return low
    if value > high:
        return high
    return value

В C сигнатура int clamp(int value, int low, int high) гарантировала бы: сюда придут только int. Передача указателя несовместимого типа (например, char* там, где ожидается int*) — нарушение ограничений языка: компилятор выдаст диагностику, а с -Werror сборка просто остановится.

В Python эта функция определяется без единой ошибки и спокойно отработает на clamp("abc", "a", "z") — сравнение строк поддерживается, функция вернёт строку. А вот clamp([1, 2], 0, 10) упадёт с TypeError: '<' not supported between instances of 'list' and 'int' — но только в момент вызова, и только если эта ветка реально исполнится. Если в тестах вы гоняли только числа, ошибка приедет в продакшен.

Вывод: «функция определена без ошибок» не означает вообще ничего о корректности типов внутри неё. Единственный сигнал — фактическое исполнение с реальными аргументами.

Попробуй сейчас

Сохраните в файл test_types.py:

def calculate_total_price(base_price, tax_rate, discount):
    price_with_tax = base_price * (1 + tax_rate)
    return price_with_tax - discount

run_buggy_code = False

if run_buggy_code:
    print(calculate_total_price(100, "0.2", 10))
else:
    print("Script finished without running the buggy code path.")
  1. Запустите python test_types.py. Ошибки нет?
  2. Замените run_buggy_code на True и запустите снова.

Ожидаемый результат: при первом запуске скрипт печатает сообщение и завершается успешно — ошибка есть в коде, но ветка не исполнялась. После True он падает на строке price_with_tax = base_price * (1 + tax_rate) с TypeError: unsupported operand type(s) for +: 'int' and 'str', потому что нельзя сложить int (1) и str ("0.2"). Проверка типа произошла ровно в момент выполнения операции.

Получилось, если…

Вы поняли материал, если для незнакомой функции можете сразу сказать: «эту ошибку в C поймал бы компилятор, а здесь её поймает только тест/вызов с такими-то данными» — и предложить конкретный входной пример, который её вскрывает.

Вывод

Компилятор C проверяет типы для всего кода сразу, до запуска. Python проверяет типы только для той строки и той ветки, что реально исполнилась с реальными данными. Отсутствие ошибки при запуске не значит отсутствие ошибки — значит, эта ветка ещё не тронута. Ответственность переходит к вам, тестам и статическим анализаторам.

flowchart LR
    subgraph C
        A1[Весь исходный код] --> A2[Компилятор проверяет типы везде] --> A3[Бинарник: типы проверены]
    end
    subgraph Python
        B1[Весь исходный код] --> B2[Интерпретатор: типы не проверяются заранее]
        B2 --> B3[Строка выполнилась?]
        B3 -->|да| B4[Проверка типа именно сейчас]
        B3 -->|нет, ветка не тронута| B5[Ошибка типа не найдена]
    end
покрытие проверкой — весь код в C и только исполненные ветки в Python

AI-generated · source-grounded review

🛡 Fact-checked: 2 risky claims verified · 3 removed · confidence: high · figures: 2
[softened] В C передача char* в параметр типа int* не даст собрать программу
Это нарушение ограничений языка, но компиляторы по умолчанию выдают диагностику/предупреждение; остановка сборки гарантирована лишь с -Werror
[removed] В Python использование значения до инициализации «обычно тихо работает»
Обращение к несвязанному имени даёт NameError/UnboundLocalError; формулировка вводила в заблуждение
[removed] calculate_total_price(100, "0.2", 10) падает с «can only concatenate str (not int) to str» на операции *
Фактически TypeError: unsupported operand type(s) for +: 'int' and 'str' на выражении 1 + tax_rate; исправлено
[verified] Тип принадлежит объекту, а не имени; имя — привязка к объекту
Прямо подтверждено разделами базы знаний об объектной модели и динамической типизации
[verified] clamp([1,2], 0, 10) даёт TypeError: '<' not supported between instances of 'list' and 'int'
Стандартное сообщение CPython для сравнения list и int
[removed] Строка таблицы A «использование значения до инициализации → в Python обычно тихо работает» удалена: в Python обращение к несвязанному имени даёт NameError/UnboundLocalError, формулировка вводила в заблуждение
[removed] Утверждение B «компилятор не позволит даже собрать программу» при передаче char* вместо int* смягчено до «выдаст диагностику; с -Werror сборка остановится»
[removed] Ожидаемое сообщение об ошибке в практике B исправлено: TypeError возникает на операции + ('int' and 'str'), а не «can only concatenate str» и не на *

A second model re-checked this lesson's claims and corroborated 3 of 5 , and could not confirm 2 either way. This is incomplete corroboration, not a disagreement.

Key concepts: runtime typing duck typing категории ошибок
Tell me more 🔒 Didn't understand — explain simply 🔒 Show examples 🔒 Sources 🔒

On your own course these buttons answer instantly, quizzes track what you've mastered, and lessons adapt to your gaps. Write my course

Check yourself

1. В чём принципиальное отличие проверки типов в Python от C?
2. Функция в Python определена без синтаксических ошибок. Что это гарантирует о корректности типов внутри неё?
3. Программист на C написал Python-функцию, которая некорректно вызывается в одной из веток условного оператора. Когда будет обнаружена ошибка типа?
On your own course, these are marked as you answer