Wrapping a class's method in a "boilerplate" Python decorator will treat that method as a regular function and make it lose its __self__ attribute that refers to the class instance object.  Can this be avoided?
Take the following class:
class MyClass(object):
    def __init__(self, a=1, b=2):
        self.a = a
        self.b = b
    def meth(self):
        pass
If meth() is undecorated, MyClass().meth.__self__ refers to an instance method and enables something like setattr(my_class_object.meth.__self__, 'a', 5).
But when wrapping anything in a decorator, only the function object is passed; the object to which it is actually bound is not passed on along with it. (See this answer.)
import functools
def decorate(method):
    @functools.wraps(method)
    def wrapper(*args, **kwargs):
        # Do something to method.__self__ such as setattr
        print(hasattr(method, '__self__'))
        result = method(*args, **kwargs)
        return result
    return wrapper
class MyClass(object):
    def __init__(self, a=1, b=2):
        self.a = a
        self.b = b
    @decorate
    def meth(self):
        pass
MyClass().meth()
# False            <--------
Can this be overriden?
Your main misunderstanding here is order of operation.
When the decorate() decorator is called, meth() is not a method yet - it is still a function - it is only when the class block is over that meth is transformed into a method by the metaclass descriptors! - that's why it doesn't have __self__ (yet).
In other words, to decorate methods you have to ignore the fact that they are methods and treat them as normal functions - because that's what they are when the decorator is called.
In fact, the original meth function will never turn into a method - instead the function wrapper you returned from the decorator will be part of the class and will be the one that will get the __self__ attribute later.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With