Почему метод может ссылаться на неопределенную переменную?

Я новичок в python и пытаюсь прочитать исходный код Bottle.py

В документе мы должны

from bottle import route, run

использовать бутылку.

Я пытаюсь прочитать исходный код, где маршрут - это просто функция, определенная в строке 2443

# Shortcuts for common Bottle methods.
# They all refer to the current default application.

def make_default_app_wrapper(name):
    ''' Return a callable that relays calls to the current default app. '''
    @functools.wraps(getattr(Bottle, name))
    def wrapper(*a, **ka):
        return getattr(app(), name)(*a, **ka)
    return wrapper

route = make_default_app_wrapper('route')

в make_default_app_wrapper приложение вызывается, но приложение определяется в строке 3325

app = default_app = AppStack()

поэтому, когда вызывается функция make_default_app_wrapper, не должно быть объекта с именем app (наверное?), так как же возвращаемая функция знает, на что указывает приложение? Я что-то не так понял?


person Coo    schedule 12.05.2013    source источник


Ответы (1)


Когда вызывается make_default_app_wrapper, он определяет wrapper, но сам wrapper не вызывается. Только когда вызывается wrapper (или route), необходимо определить app.

Когда wrapper определено, Python анализирует строку

return getattr(app(), name)(*a, **ka)

и определяет, что простое имя app не является локальной переменной, поскольку оно никогда не было в левой части присваивания или указано в качестве аргумента. Это влияет только на то, как будет искаться app (когда вызывается wrapper), в это время он не пытается искать значение app.

Когда wrapper вызывается и Python выполняет оператор

return getattr(app(), name)(*a, **ka)

Python ищет значение для app в глобальном пространстве имен. Обратите внимание, что значение app может даже меняться от одного вызова wrapper к другому. Питон об этом не знал. значение app не является жестко заданным. Он просматривается каждый раз, когда вызывается wrapper.

person unutbu    schedule 12.05.2013
comment
Таким образом, ключевым моментом является определение app при вызове make_default_app_wrapper. Если app определено, это замыкание, если нет, wrapper ищет app при каждом вызове. - person Coo; 12.05.2013
comment
Ну, не совсем -- даже если app определено при вызове make_default_app_wrapper, app будет искаться каждый раз. - person unutbu; 12.05.2013
comment
А? Тогда что, если я определил app и хочу вызвать его независимо от того, определены ли другие app позже или нет? - person Coo; 12.05.2013
comment
Может быть, я неправильно вас понял. Если app определено в глобальном пространстве имен при вызове make_default_app_wrapper, app будет искаться каждый раз. Если app определено внутри make_default_app_wrapper, то да, make_default_app_wrapper является замыканием, и значение app будет каждый раз одинаковым. - person unutbu; 12.05.2013
comment
Ой! Я понимаю. Я неправильно понял закрытие. Я думал, что он просто берет то, что определено ранее, и сохраняет ссылку. - person Coo; 12.05.2013