[Python] How to get functools.lru_cache to return new instances?

Discussão em 'Python' iniciado por Stack, Novembro 29, 2025.

  1. Stack

    Stack Membro Participativo

    I use Python's lru_cache on a function which returns a mutable object, like so:

    import functools

    @functools.lru_cache()
    def f():
    x = [0, 1, 2] # Stand-in for some long computation
    return x


    If I call this function, mutate the result and call it again, I do not obtain a "fresh", unmutated object:

    a = f()
    a.append(3)
    b = f()
    print(a) # [0, 1, 2, 3]
    print(b) # [0, 1, 2, 3]


    I get why this happens, but it's not what I want. A fix would be to leave the caller in charge of using list.copy:

    a = f().copy()
    a.append(3)
    b = f().copy()
    print(a) # [0, 1, 2, 3]
    print(b) # [0, 1, 2]


    However I would like to fix this inside f. A pretty solution would be something like

    @functools.lru_cache(copy=True)
    def f():
    ...


    though no copy argument is actually taken by functools.lru_cache.

    Any suggestion as to how to best implement this behavior?

    Edit


    Based on the answer from holdenweb, this is my final implementation. It behaves exactly like the builtin functools.lru_cache by default, and extends it with the copying behavior when copy=True is supplied.

    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]

    Continue reading...

Compartilhe esta Página