aiocache icon indicating copy to clipboard operation
aiocache copied to clipboard

Strange behaviour for @multi_cached decorator

Open alvassin opened this issue 4 months ago • 5 comments

When i specify key_builder for @multi_cached decorator, it makes two strange things: it modifies input for target function, and also return modified keys:

import asyncio

from aiocache import multi_cached


def key_builder(key, f, *args, **kwargs):
    return key, args[0]


class MyClass:
    @multi_cached(
        keys_from_attr='ids',
        key_builder=key_builder,
    )
    async def example(self, ids):
        print('example called', ids)
        return {id_: id_ for id_ in ids}


async def main():
    obj = MyClass()
    # {
    #   (1, <__main__.MyClass object at 0x10d1bf490>): (1, <__main__.MyClass object at 0x10d1bf490>),
    #   (2, <__main__.MyClass object at 0x10d1bf490>): (2, <__main__.MyClass object at 0x10d1bf490>)
    # }
    results = await obj.example(ids=[1, 2])
    print(results)


asyncio.run(main())

I expect that this decorator at least should not change input parameters for target function. If i call MyClass().example(ids=[1,2]) i should get ids=[1,2] in my target function.

I also expected that result keys of function MyClass.example(ids=[1,2]) would also be unchanged - it is very confusing that decorator changes function result value. It should just perform caching.

alvassin avatar Jul 31 '25 10:07 alvassin

A key should be a string, not a tuple. See the examples: https://github.com/aio-libs/aiocache/blob/ceb0b5ed6e808f21c4b5ae2dab6fc38c0b01c0b6/examples/alt_key_builder.py#L62-L79

v1 will have type annotations etc. that should help make this more obvious.

Dreamsorcerer avatar Jul 31 '25 11:07 Dreamsorcerer

@Dreamsorcerer thank you for response. Anyway, even if i make str keys, decorator changes input parameters for target function. It is very confusing.

In my opinion, decorator should not force you to change how do you work with your entities - current implementation requires me to workaround strange keys, that are really needed only for inner cache implementation for this decorator.

I expected decorator is just plug-in and go, and should not change interfaces for my business logic.

I'll write implementation for myself in different package, but just to share: current implementation is very confusing.

alvassin avatar Aug 01 '25 11:08 alvassin

Yeah, that doesn't sound right. Can you create a PR with a test reproducing the problem?

Dreamsorcerer avatar Aug 01 '25 11:08 Dreamsorcerer

Actually, I think this is expected behaviour. It's unique to multi_cached: https://github.com/aio-libs/aiocache/blob/ceb0b5ed6e808f21c4b5ae2dab6fc38c0b01c0b6/aiocache/decorators.py#L169-L187

I'm not too clear on the logic of why this exists...

Dreamsorcerer avatar Aug 01 '25 11:08 Dreamsorcerer

I think your expectation probably makes sense though. I'm happy to accept a PR changing this behaviour in v1.

Dreamsorcerer avatar Aug 01 '25 11:08 Dreamsorcerer