Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Member function decorator and self argument

The following minimal example of a decorator on a member function:

def wrap_function(func):
    def wrapper(*args, **kwargs):
        print(args)
        print(kwargs)
    return wrapper

class Foo:
    @wrap_function
    def mem_fun(self, msg):
        pass

foo = Foo()
foo.mem_fun('hi')

outputs:

(<__main__.Foo object at 0x7fb294939898>, 'hi')
{}

So self is one of the args.

However when using a wrapper class:

class WrappedFunction:
    def __init__(self, func):
        self._func = func

    def __call__(self, *args, **kwargs):
        print(args)
        print(kwargs)

def wrap_function(func):
    return WrappedFunction(func)

class Foo:
    @wrap_function
    def mem_fun(self, msg):
        pass

foo = Foo()
foo.mem_fun('hi')

the output is:

('hi',)
{}

So the self, that references the Foo object, is not accessible in the body of __call__ of the WrappedFunction object.

How can I make it accessible there?

like image 248
Tobias Hermann Avatar asked Oct 17 '22 14:10

Tobias Hermann


1 Answers

You're losing the reference to your bounded instance by wrapping the function logic (but not the instance) and redirecting it to a class instance - at that point, the class instance's own self applies instead of the wrapped instance method as it gets lost in the intermediary decorator (wrap_function()).

You either have to wrap the call to the wrapped function and pass *args/**kwargs to it, or just make a proper wrapper class instead of adding an intermediary wrapper:

class WrappedFunction(object):

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print(args)
            print(kwargs)
            # NOTE: `WrappedFunction` instance is available in `self`
        return wrapper

class Foo:
    @WrappedFunction()  # wrap directly, without an intermediary
    def mem_fun(self, msg):
        pass

foo = Foo()
foo.mem_fun('hi')
# (<__main__.Foo object at 0x000001A2216CDBA8>, 'hi')
# {}
like image 114
zwer Avatar answered Nov 02 '22 12:11

zwer