Как работает `matplotlib._logged_cached`? - PullRequest
0 голосов
/ 19 июня 2020

Следующий код взят из файла __init__ Matplotlib:

def _logged_cached(fmt, func=None):
    """
    Decorator that logs a function's return value, and memoizes that value.

    After ::

        @_logged_cached(fmt)
        def func(): ...

    the first call to *func* will log its return value at the DEBUG level using
    %-format string *fmt*, and memoize it; later calls to *func* will directly
    return that value.
    """
    if func is None:  # Return the actual decorator.
        return functools.partial(_logged_cached, fmt)

    called = False
    ret = None

    @functools.wraps(func)
    def wrapper(**kwargs):
        nonlocal called, ret
        if not called:
            ret = func(**kwargs)
            called = True
            _log.debug(fmt, ret)
        return ret

    return wrapper

Вопрос: Как работает кеширование в приведенной выше функции? Не будут ли локальные переменные _logged_cached повторно инициализироваться при каждом вызове?

Насколько я понимаю, локальные переменные удаляются после возврата из функции (верно?). Если так, то кеширование работать не будет. Тем не менее, в документации говорится, что декорированная функция будет возвращать один и тот же объект при каждом вызове - и это так. Но как?

1 Ответ

0 голосов
/ 20 июня 2020

Причина, по которой кеширование работает, заключается в концепции, называемой закрытием. Вы правильно понимаете, что локальные переменные удаляются после выхода из функции, но переменные, используемые здесь для кеширования, не являются локальными для внутренней функции.

Если вы используете _logged_cached декоратор для функции, функция будет по существу заменить вложенной функцией wrapper. Эта wrapper функция при возврате становится закрытием (функциональным объектом), который запоминает нелокальные переменные в охватывающей области. Таким образом, у него будет отображение, которое запоминает переменные called и ret. Каждый раз, когда вы вызываете объект функции (декорированную функцию), внутренняя область видимости будет иметь called и ret, доступные для использования.

Обычно они будут доступны только для чтения во внутренней функции, но используя ключевое слово nonlocal, внутренняя функция действительно может изменять / обновлять значения переменных called и ret в закрытии. Таким образом, упомянутое нами ранее отображение, сохраненное в объекте функции, обновляет свои значения, и каждый последующий вызов декорированной функции будет использовать те же значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...