Я использую Python lru_cache
для функции, которая возвращает изменяемый объект, например:
import functools
@functools.lru_cache()
def f():
x = [0, 1, 2] # Stand-in for some long computation
return x
Если я вызываю эту функцию, изменяю результат и вызываю его снова,Я не получаю «свежий», неизмененный объект:
a = f()
a.append(3)
b = f()
print(a) # [0, 1, 2, 3]
print(b) # [0, 1, 2, 3]
Я понимаю, почему это происходит, но это не то, что я хочу.Исправление будет состоять в том, чтобы оставить вызывающего абонента ответственным за использование list.copy
:
a = f().copy()
a.append(3)
b = f().copy()
print(a) # [0, 1, 2, 3]
print(b) # [0, 1, 2]
Однако я хотел бы исправить это внутри f
.Хорошим решением было бы что-то вроде
@functools.lru_cache(copy=True)
def f():
...
, хотя functools.lru_cache
.
фактически не принимается аргумент copy
. Любое предложение о том, как лучше всего реализовать это поведение?
Edit
Исходя из ответа от holdenweb, это моя последняя реализация.Он ведет себя точно так же, как встроенный functools.lru_cache
по умолчанию, и расширяет его при копировании, когда предоставляется copy=True
.
import functools
from copy import deepcopy
def lru_cache(maxsize=128, typed=False, copy=False):
if not copy:
return functools.lru_cache(maxsize, typed)
def decorator(f):
cached_func = functools.lru_cache(maxsize, typed)(f)
@functools.wraps(f)
def wrapper(*args, **kwargs):
return deepcopy(cached_func(*args, **kwargs))
return wrapper
return decorator
# Tests below
@lru_cache()
def f():
x = [0, 1, 2] # Stand-in for some long computation
return x
a = f()
a.append(3)
b = f()
print(a) # [0, 1, 2, 3]
print(b) # [0, 1, 2, 3]
@lru_cache(copy=True)
def f():
x = [0, 1, 2] # Stand-in for some long computation
return x
a = f()
a.append(3)
b = f()
print(a) # [0, 1, 2, 3]
print(b) # [0, 1, 2]