rah*_*hmu 6 python internals decorator memoization
以下函数旨在用作存储已计算值的结果的装饰器.如果之前已经计算过该参数,该函数将返回存储在cache字典中的值:
def cached(f):
f.cache = {}
def _cachedf(*args):
if args not in f.cache:
f.cache[args] = f(*args)
return f.cache[args]
return _cachedf
Run Code Online (Sandbox Code Playgroud)
我意识到(错误地)cache不需要是函数对象的属性.事实上,以下代码也适用:
def cached(f):
cache = {} # <---- not an attribute this time!
def _cachedf(*args):
if args not in cache:
cache[args] = f(*args)
return cache[args]
return _cachedf
Run Code Online (Sandbox Code Playgroud)
我很难理解cache对象如何在多个调用中持久化.我尝试多次调用多个缓存函数,但找不到任何冲突或问题.
任何人都可以帮助我理解cache即使在_cachedf函数返回后变量仍然存在?
Sve*_*ach 12
您在此处创建一个闭包:该函数_cachedf()关闭cache来自封闭范围的变量.cache只要函数对象存在,它就会保持活动状态.
编辑:也许我应该添加一些关于它如何在Python中工作的细节以及CPython如何实现它.
让我们看一个更简单的例子:
def f():
a = []
def g():
a.append(1)
return len(a)
return g
Run Code Online (Sandbox Code Playgroud)
交互式解释器中的示例用法
>>> h = f()
>>> h()
1
>>> h()
2
>>> h()
3
Run Code Online (Sandbox Code Playgroud)
在编译包含该函数的模块期间f(),编译器会看到该函数g()引用了a封闭范围中的名称,并将该外部引用存储在与该函数对应的代码对象中f()(具体而言,它将名称添加a到f.__code__.co_cellvars).
那么在调用函数时会发生什么f()?第一行创建一个新的列表对象并将其绑定到名称a.下一行创建一个新的函数对象(使用在编译模块期间创建的代码对象)并将其绑定到名称g.此时g()不执行主体,最后返回funciton对象.
由于代码对象f()具有a本地函数引用该名称的注释,因此在f()输入时将创建此名称的"单元格"
.此单元格包含对a绑定的实际列表对象的引用,并且该函数g()获取对此单元格的引用.这样,即使函数f()退出,列表对象和单元格也会保持活动状态.
| 归档时间: |
|
| 查看次数: |
2052 次 |
| 最近记录: |