有没有办法访问用装饰器定义的 Python 函数的命名空间?



假设我使用缓存装饰器来定义一个新函数,如下所示:

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的命名空间中。此字典不能在外部全局范围内直接访问。

是否可以通过函数triple的某种属性访问此cache字典?

注意:我想知道是否可以在不通过cached定义中的cache_funcy.cache = cache之类的东西明确地将cachetriple属性来做到这一点。

实际上,这个字典并不存储在函数的本地命名空间中,它是一个自由变量,所以它存储在函数闭包中。在 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__

最新更新