Давайте попробуем более простой кусок кода с похожим поведением:
pub = None
def func():
return pub
pub = "thing"
func() # returns "thing"
Вы можете ожидать, что func
вернет None
, потому что это значение pub
, когда определено func
. Но Python фактически обрабатывает код следующим образом:
- создайте переменную в пространстве имен модуля с именем 'pub' и присвойте ей значение
None
- создайте переменную в пространстве имен модуля с именем 'func' и сделайте так, чтобы она указывала на блок кода функции. Код функции представляет собой скрипт для выполнения следующих действий:
- найти переменную с именем 'pub' в пространстве имен модуля
- получить значение этой переменной
- вернуть это значение
- присваивать значение 'thing' переменной 'pub' в пространстве имен модуля
- найдите переменную 'func' в пространстве имен модуля и вызовите код, на который она указывает.
Здесь важно отметить, что шаг 2 ничего не делает с текущим значением pub
. Он просто определяет функцию, которая (в конечном итоге) ищет pub
и что-то делает со своим значением. pub
даже не нужно определять, когда Python переходит к шагу 2.
Когда Python переходит к шагу 4, то есть когда код в func
(определенный на шаге 2) фактически выполняется. На этом этапе функция (впервые) ищет переменную pub
в пространстве имен модуля. Затем он получает значение и работает с ним. Поскольку это происходит после шага 3, функция обнаруживает, что pub
имеет значение "вещь".
Я предполагаю, что ключевая идея здесь в том, что оператор def
просто создает функцию как абстрактный блок кода. Он не ищет текущие значения переменных модуля и не присоединяет их к функции. Вместо этого сама функция ищет эти переменные и извлекает их значения при последующем вызове.