有没有办法访问用装饰器定义的 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定义的名称空间中。该字典在外部全局范围内不能直接访问。


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


注意:我想知道是否可以在不显式创建cache属性的情况下执行此操作,triple例如cache_funcy.cache = cache在cached.


一只斗牛犬
浏览 160回答 1
1回答

catspeake

实际上,这个 dict 并没有存储在函数的本地命名空间中,它是一个自由变量,所以它存储在函数闭包中。在 Python 2 中,请考虑:In [1]: def cached(funcy):&nbsp; &nbsp;...:&nbsp; &nbsp; &nbsp;cache = dict()&nbsp; &nbsp;...:&nbsp; &nbsp; &nbsp;def cache_funcy(x):&nbsp; &nbsp;...:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if x in cache:&nbsp; &nbsp;...:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return cache[x]&nbsp; &nbsp;...:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else:&nbsp; &nbsp;...:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;print cache&nbsp; &nbsp;...:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;result = funcy(x)&nbsp; &nbsp;...:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cache[x] = result&nbsp; &nbsp;...:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return result&nbsp; &nbsp;...:&nbsp; &nbsp; &nbsp;return cache_funcy&nbsp; &nbsp;...:&nbsp; &nbsp;...: @cached&nbsp; &nbsp;...: def triple(x):&nbsp; &nbsp;...:&nbsp; &nbsp; &nbsp;return 3*x&nbsp; &nbsp;...:In [2]: triple(1){}Out[2]: 3In [3]: triple(2){1: 3}Out[3]: 6现在:In [5]: triple.func_closureOut[5]:(<cell at 0x10e4e7be8: dict object at 0x10e7ec910>,&nbsp;<cell at 0x10e7b2590: function object at 0x10e81ede8>)第一个单元格包含dict,第二个单元格包含正在装饰的函数(它也是一个自由变量)。因此,您可以使用:In [6]: triple.func_closure[0].cell_contentsOut[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>,&nbsp;<cell at 0x1026dbf48: function object at 0x1028e59d8>)实际上,在 Python 2 中,自 Python 2.6 起,添加了这些下划线属性是为了向前兼容,因此除非您使用的是低于 Python 2.6 的版本,否则该属性也存在。因此,出于兼容性原因,您可能应该使用 __closure__
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python