pythonpython-decorators

Wrap class method with argument(s) only once


There are two classes and I want to wrap item.foo method only once, to prevent cache = {param1: 'param_value'} being reinited

class Foo:
    _count = 0

    def foo(self, param2):
        self._count += param2


class Bar:
    _collection = [Foo(), Foo(), Foo()]

    def bar(self, param1, param2):
        for item in self._collection:
            wrapped_function = wrapper(item.foo, param1)
            wrapped_function(param2)


def wrapper(func, param1):
    # some database call or whatever
    cache = {param1: 'param_value'}

    def _wrapper(*args, **kwargs):
        # access value to read
        print(cache[param1])
        return func(*args, **kwargs)
    return _wrapper


bar = Bar()
bar.bar(1, 2)

It can be achieved if wrapper had no params in it and was used as a simple decorator, but I have to pass a param1 in it, though it's always the same. I also can save cache = {param1: 'param_value'} before the cycle in def bar and pass it as the parameter, but I was wondering if there any other way to accomplish it.

Kinda can't wrap my head around it(pun intended)


Solution

  • It sounds like you want to wrap Foo.foo, not item.foo (which is different bound method for each value of foo. Something like

    class Bar:
        _collection = [Foo(), Foo(), Foo()]
    
        def bar(self, param1, param2):
            wrapped_function = wrapper(Foo.foo, param1)
            for item in self._collection:
                wrapped_function(item, param2)
    

    It's more complicated if you only want to apply the wrapper once per unique type of object in _collection, as you need to build a cache of wrapped functions. Something like

    class Bar:
        _collection = [Foo(), Foo(), Foo()]
        wrap_cache = {}
    
        def bar(self, param1, param2):
            for item in self._collection:
                itype = type(item)
                if itype.foo not in wrap_cache:
                    wrap_cache[itype] = wrapper(itype.foo, param1)
                wrapped_function = wrap_cache[itype]
                wrapped_function(param2)