I'm a little late to the party, but late is better than never eh? :)
We can do this by decorating our class method with a decorator which is itself a class object, say B
, and then hook into the moment when Python calls B.__get__
so to fetch the method. In that __get__
call, which will be passed both the owner class and the newly generated instance of that class, you can elect to either insert your method/variable into the original owner class, or into the newly defined instance.
class B(object):
def __init__(self, f):
self.f = f
def __call__(self, *args, **kwargs):
return self.f(*args, **kwargs)
def __get__(self, instance, owner):
instance.inserted = True
# owner.inserted = True
def wrapper(*args, **kwargs):
return self(instance, *args, **kwargs)
return wrapper
class A:
@B
def method(self):
pass
if __name__ == "__main__":
a = A()
a.method()
b = A()
print(hasattr(a, 'inserted'))
print(hasattr(b, 'inserted'))
In this example, we're wrapping def method(self)
with @B
. As written, the inserted attribute inserted
will only persist in the a
object because it's being applied to the instance. If we were to create a second object b
as shown, the inserted
attribute is not included. IE, hasattr(a, 'inserted')
prints True
and hasattr(b, 'inserted')
prints False
. If however we apply inserted
to the owner
class (as shown in the commented out line) instead, the inserted attribute will persist into all future A()
objects. IE hasattr(a, 'inserted')
prints True
and hasattr(b, 'inserted')
prints True
, because b
was created after a.method()
was called.