Currently I use the following technique:
def Myfb(param1, param2, firstTime):
if firstTime:
global a = compute()
global b = compute2()
global a
global b
c = doNormalExecution(param1, param2, a, b)
Is there a more elegant way? I don't like creating globals
The technique is called memoization. The functools module has an lru_cache
function that does what you want.
from functools import lru_cache
@lru_cache(maxsize=None)
def Myfb(param1, param2):
b = doNormalExecution(a)
The python docs have more information like what maxsize is and how lru_cache works so that you can implement it suitably.
You can use a generator:
def Myfb():
a = compute()
while True:
param1, param2 = yield
b = doNormalExecution(a, param1, param2)
yield b
Here you have a live example
Example code:
def compute():
return 10
def doNormalExecution(a, b, c):
return a + b + c
def Myfb():
a = compute()
while True:
param1, param2 = yield
b = doNormalExecution(a, param1, param2)
yield b
f = Myfb()
next(f)
for a, b in zip(range(10), range(10)):
print(f.send((a, b)))
next(f)
You can create a custom callable that will maintain it's own state:
class MyFB(object):
_sentinel = object()
def __init__(self):
self._a = self._sentinel
self._b = self._sentinel
def __call__(self, param1, param2, reinit=False):
if reinit or self._a is self._sentinel or self._b is self._sentinel:
self._a = compute_a()
self._b = compute_b()
return doNormalExecution(param1, param2, self._a, self._b)
myfb = MyFB()
# now use `myfb` like an ordinary function
Seeing as compute1() and compute2() don't take arguments, you could use functools to cache their results. (Unless they have side effects.)
from functools import cache
@cache
def compute():
#do complicated stuff first time called
return result
@cache
def compute2():
#do complicated stuff first time called
return result
def Myfb(param1, param2):
a = compute()
b = compute2()
c = doNormalExecution(param1, param2, a, b)
If you don't pass any parameters to a function, use this decorator (I had it lying around):
import functools
def lazy(func):
""" Decorator which only actually runs a function the first time it is
called and stores the result to be returned on later calls.
Usage:
@lazy
def func_to_be_only_run_once():
...
"""
FLAG = object()
result = FLAG
@functools.wraps(func)
def inner():
nonlocal result
if result is FLAG:
result = func()
return result
return inner
If you have one or more arguments that change (including self
) use functools.lru_cache
Here's a cool way to do it using closures.
def closure(firstTime=True):
def Myfb():
nonlocal firstTime
if firstTime:
print("First time.")
firstTime = False
return Myfb
myfb = closure()
myfb()
myfb()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.