yegle
yegle

Reputation: 5875

Is it possible in Python to decorate a method in class using method in instance

I'm trying to wrap a function when defining the class, use method in this class's instance

Below is a code that works

class A(object):   
    def __init__(self):    
        pass       

    @self_decorator 
    def to_be_decorated(self):
        pass       

def self_decorator(fn):    
    from functools import wraps
    @wraps(fn)     
    def wrapper(*args, **kwargs):
        self = args[0]     
        return self.app.route('/twip')(fn(*args, **kwargs))

    return wrapper

What I actually tries to get:

class A(object):   
    def __init__(self):    
        self.app = APP()    

    @self.app.wrapper_function # which apparently doesn't work
    def to_be_decorated(self):
        pass

So, is it possible for my way of decorating to work?

Upvotes: 1

Views: 111

Answers (2)

abarnert
abarnert

Reputation: 365657

A decorator is just a function that gets called at the time of definition.

When you write this:

@self.app.wrapper_function # which apparently doesn't work
def to_be_decorated(self):
    pass

it's roughly the same as writing this:

def to_be_decorated(self):
    pass
to_be_decorated = self.app.wrapper_function(to_be_decorated)

Once you see it that way, it's obvious why this doesn't work, and couldn't possibly work.

First, A's class definition doesn't have a self variable, nor does A have a member app that could be accessed even if it did. Instead, each instance of A will have its own unique self.app.

And even if you wish the interpreter could just "do what I mean", if you think about it, that can't mean anything. You want to call "the" self.app.wrapper_function method, but there is no such thing. Unless you read through all of the relevant code everywhere the method could be defined or redefined, there's absolutely no guarantee that the self.app.wrapper_function from different instances of A will even have the same underlying func_code. But, even if they did, self.app.wrapper_function is a bound method—a method bound together with the object it's called on—so they're still all different from each other.

There are plenty of ways around this, but they're all going to be the same trick: Use some kind of indirection to get a function which isn't a member of self.app or self, and references self.app at call time. This is basically what your self_decorator does, and it's unavoidable.

Upvotes: 0

JBernardo
JBernardo

Reputation: 33397

At the class definition there's no self as the class do not exists yet and cannot be instantiated.

You can use

class A(object):
    app = APP()

    @app.wrapper_function
    def to_be_decorated(self):
        pass

But that would be a class variable.

Upvotes: 2

Related Questions