Глава 13 · Автоматизация с помощью функций

Стек вызовов и traceback

Функции, вызывающие функции, образуют стек ожидающих вызовов — и traceback из главы 3 на самом деле показывает именно этот стек в момент ошибки.

Кадр вызова (call frame)

Когда функция вызывается, Python создаёт временный «контейнер» для этого конкретного вызова — с параметрами, локальными именами и отметкой, куда вернуться после завершения:

call_frame.py
def area(width, height):
    return width * height

area(5, 3)
width5height3
Кадр вызова area(5, 3): параметры существуют, пока этот конкретный вызов не завершится

Функции могут вызывать другие функции

vlozhennye_vyzovy.py
def calculate_tax(amount):
    return amount * 0.2

def calculate_invoice(amount):
    tax = calculate_tax(amount)
    return amount + tax

calculate_invoice(100)

Пока calculate_tax() выполняется, вызов calculate_invoice() не заканчивается — он «ждёт» на паузе. Python отслеживает все ожидающие вызовы в структуре, которую называют стеком вызовов.

Стек растёт и уменьшается

main← верх стека
Шаг 1 — выполняется основная программа
calculate_invoice()← верх стекаmain
Шаг 2 — main вызвала calculate_invoice()
calculate_tax()← верх стекаcalculate_invoice()main
Шаг 3 — calculate_invoice вызвала calculate_tax(); стек на пике
calculate_invoice()← верх стекаmain
Шаг 4 — calculate_tax() вернула результат и исчезла со стека
Последним вошёл — первым вышел
Стек вызовов растёт с каждым новым вызовом и уменьшается с каждым завершением — самый недавний вызов всегда наверху и завершается первым. Это называют принципом LIFO (Last In, First Out).

Traceback — это и есть снимок стека вызовов

Вспомним отладку из главы 3: когда возникает ошибка, Python печатает traceback — и это буквально показывает цепочку вызовов, которая привела к ошибке:

traceback_primer.py
def divide(a, b):
    return a / b

def calculate():
    return divide(10, 0)

def main():
    calculate()

main()
Traceback (most recent call last):
  File "example.py", line 8, in <module>
    main()
  File "example.py", line 6, in main
    calculate()
  File "example.py", line 4, in calculate
    return divide(10, 0)
  File "example.py", line 2, in divide
    return a / b
ZeroDivisionError: division by zero
Каждая строка traceback — это один кадр из стека вызовов на момент ошибки
Читаем traceback снизу вверх
Самая нижняя строка — сама ошибка. Строка над ней — где именно она произошла (divide). Выше — кто её вызвал (calculate), и ещё выше — кто вызвал того (main). Traceback — это ровно тот стек вызовов, который мы только что визуализировали, показанный в момент, когда что-то пошло не так.
Практика: читаем стек вызовов и traceback
Интерактивный ноутбук прямо в браузере — Python 3.14 через Pyodide, без установки
Открыть практику →