Как python реализует взаимную рекурсию?

Переходя к python с фоном C/Java, мне недавно пришлось реализовать взаимную рекурсию, но что-то в python беспокоит меня:

поскольку программа python интерпретируется по строкам, если у меня есть две функции один за другим в одном файле python:

def A(n):
    B(n-1)
# if I add A(1) here, it gives me an error
def B(n):
    if n <= 0:
        return
    else:
        A(n-1)

Когда интерпретатор читает A, B еще не определен, однако этот код не дает мне ошибку

TL; DR Я понимаю, что, когда def интерпретируется, python добавляет запись в какое-то локальное пространство имен locals() с {"function name": function address}, но что касается тела функции, он выполняет только проверку синтаксиса:

def A():
    blabla # this will give an error

def B():
    print x # even though x is not defined, this does not give an error
    A()     # same as above, NameError is only detected during runtime

Ответ 1

A SyntaxError будет обнаружен во время компиляции, но большинство других ошибок (NameError, ValueError и т.д.) будут обнаружены только во время выполнения, а затем только при вызове этой функции.

", если я написал функцию, если ее не вызвал в моем тесте.." - и именно поэтому вы должны проверить все.

Некоторые IDE будут вызывать предупреждения в разных ситуациях, но лучший вариант - провести тщательное тестирование самостоятельно. Таким образом, вы также можете проверить наличие ошибок, возникающих с помощью таких факторов, как пользовательский ввод, которые автоматические проверки IDE не будут покрываться.

Ответ 2

В строке B(n-1) говорится: "Когда этот оператор выполняется, найдите в модуле некоторую функцию B, затем вызовите ее с параметрами n-1". Поскольку поиск выполняется, когда функция выполняется, B может быть определена позже.

(Кроме того, вы можете полностью перезаписать B с помощью другой функции, а A будет вызывать новый B, но это может привести к некорректному коду.)

Если вы беспокоитесь о том, что не поймаете вызовы несуществующих функций, вы можете попробовать использовать инструменты статического анализа. Помимо этого, убедитесь, что вы тестируете свой код.

Ответ 3

Когда интерпретатор читает A, B еще не определен, однако этот код не дает мне ошибку

Причина, по которой интерпретатор python не дает ошибку, можно найти из docs, который называется переслать ссылку технически:

Разрешение имен свободных переменных возникает во время выполнения, а не во время компиляции.