是否有一种惯用的方法来实现"一次方法",即:一种方法,其返回值仅在第一次调用时得到评估?类似于以下简化代码对返回值的作用x:
class X:
def __init__(self):
self._x = None
def x(self):
if not self._x:
self._x = some_expensive_call()
return self._x
Run Code Online (Sandbox Code Playgroud)
一种方法是给函数本身一个属性,该属性仅True在第一次调用时.
>>> def once():
... if once.first_call:
... print('doing some heavy computation over here...')
... once.result = 1 + 1
... once.first_call = False
... return once.result
...
>>> once.first_call = True
>>> once()
doing some heavy computation over here...
2
>>> once()
2
Run Code Online (Sandbox Code Playgroud)
另一种选择是(ab)使用可变的默认参数.优点是您在定义函数后不必设置属性:
>>> def once(state={'first_call':True}):
... if state['first_call']:
... print('doing some heavy computation over here...')
... state['result'] = 1 + 1
... state['first_call'] = False
... return state['result']
...
>>> once()
doing some heavy computation over here...
2
>>> once()
2
Run Code Online (Sandbox Code Playgroud)
编辑:
为了完整性,如果您具有仅应计算一次的实例属性,请使用属性:
class Foo(object):
def __init__(self):
self._x = None
@property
def x(self):
if self._x is None:
self._x = self._compute_x()
return self._x
def _compute_x(self):
print('doing some heavy computation over here...')
return 1 + 1
Run Code Online (Sandbox Code Playgroud)
演示:
>>> f = Foo()
>>> f.x
doing some heavy computation over here...
2
>>> f.x
2
Run Code Online (Sandbox Code Playgroud)
从Python 3.2开始,你可以使用functools.lru_cache装饰器(但它可能对你需要的东西有点过分):
import functools
@functools.lru_cache(maxsize=1)
def once():
print("calculating expensive result")
return "expensive result"
once()
once()
Run Code Online (Sandbox Code Playgroud)
输出:
calculating expensive result # <- only prints on first call
'expensive result' # returned value on first call
'expensive result' # <- just return value on second call
Run Code Online (Sandbox Code Playgroud)
或者,您可以编写自己的装饰器:
def cache_result(func):
def wrapper(*args, **kwds):
if not wrapper.cached:
wrapper.value = func(*args, **kwds)
wrapper.cached = True
return wrapper.value
wrapper.cached = False
return functools.update_wrapper(wrapper, func)
Run Code Online (Sandbox Code Playgroud)
并在任何只想运行一次的函数上使用它并缓存结果
@cache_result
def do_once():
print('doing it once')
return 'expensive result'
Run Code Online (Sandbox Code Playgroud)