Есть ли способ получить доступ к пространству имен функции Python, определенной с помощью декоратора? - PullRequest
0 голосов
/ 24 октября 2018

Допустим, я использую декоратор кэширования для определения новой функции, например:

def cached(funcy):
    cache = dict()
    def cache_funcy(x):
        if x in cache:
            return cache[x]
        else:
            print cache
            result = funcy(x)
            cache[x] = result
            return result
    return cache_funcy

@cached
def triple(x):
    return 3*x

Четыре раза вызов функции triple приводит к следующему выводу:

>>> triple(1)
{}
3
>>> triple(2)
{1: 3}
6
>>> triple(2)
6
>>> triple(4)
{1: 3, 2: 6}
12

Насколько я понимаю, функция triple имеет доступ к словарю, который локально называется cache, поскольку этот словарь существует в пространстве имен, в котором определен triple.Этот словарь не доступен напрямую во внешней глобальной области видимости.

Возможно ли получить доступ к этому словарю cache через какой-то атрибут функции triple?

Примечание: я хочу знать, возможно ли это сделать без явного присвоения cache атрибута triple через что-то вроде cache_funcy.cache = cache в определении cached.

1 Ответ

0 голосов
/ 24 октября 2018

На самом деле, этот dict не хранится в локальном пространстве имен функции, это свободная переменная, поэтому он сохраняется в замыкании функции. В Python 2 рассмотрим:

In [1]: def cached(funcy):
   ...:     cache = dict()
   ...:     def cache_funcy(x):
   ...:         if x in cache:
   ...:             return cache[x]
   ...:         else:
   ...:             print cache
   ...:             result = funcy(x)
   ...:             cache[x] = result
   ...:             return result
   ...:     return cache_funcy
   ...:
   ...: @cached
   ...: def triple(x):
   ...:     return 3*x
   ...:

In [2]: triple(1)
{}
Out[2]: 3

In [3]: triple(2)
{1: 3}
Out[3]: 6

А теперь:

In [5]: triple.func_closure
Out[5]:
(<cell at 0x10e4e7be8: dict object at 0x10e7ec910>,
 <cell at 0x10e7b2590: function object at 0x10e81ede8>)

Первая ячейка содержит dict, вторая ячейка содержит функцию, котораябыть украшенным (что также является свободной переменной).Итак, вы можете использовать:

In [6]: triple.func_closure[0].cell_contents
Out[6]: {1: 3, 2: 6}

In [7]: triple.func_closure[0].cell_contents[2] = 'foo'

In [8]: triple(2)
Out[8]: 'foo'

Обратите внимание, атрибуты функций в Python 3 немного отличаются, здесь есть прямой атрибут __closure__, поэтому:

In [4]: triple.__closure__
Out[4]:
(<cell at 0x1026dbc78: dict object at 0x1028d1bd0>,
 <cell at 0x1026dbf48: function object at 0x1028e59d8>)

И фактически, в Python 2, начиная с Python 2.6, эти атрибуты подчеркивания были добавлены для прямой совместимости, поэтому этот атрибут также существует, если вы не используете версию ниже Python 2.6.

Так что из соображений совместимости, вы, вероятно, должны использовать __closure__

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