4

The top answer for Class method decorator with self arguments? (direct link to answer: https://stackoverflow.com/a/11731208) describes how a decorator can access attributes of the object when decorating a method.

I tried to apply this to my own code, but realized it only works when using a function as the decorator. For some reason, when using a class as the decorator, the arguments tuple no longer contains the self object. Why does this happen, and is there some other way to access the wrapped method's self?

To demonstrate:

import functools class DecoratorClass: def __init__(self, func): functools.update_wrapper(self, func) self.func = func def __call__(self, *args, **kwargs): print("args:", args) print("kwargs:", kwargs) print("Counting with:", args[0].name) self.func(*args, **kwargs) def decorator_func(func): @functools.wraps(func) def wrapper(*args, **kwargs): print("args:", args) print("kwargs:", kwargs) print("Counting with:", args[0].name) func(*args, **kwargs) return wrapper class Counter: def __init__(self, name, count): self.name = name self.count = count @decorator_func def count_a(self): for i in range(self.count): print(i) @DecoratorClass def count_b(self): for i in range(self.count): print(i) c = Counter('my counter', 3) c.count_a() print() c.count_b() 

Output:

args: (<__main__.Counter object at 0x7f4491a21970>,) kwargs: {} Counting with: my counter 0 1 2 args: () kwargs: {} Traceback (most recent call last): File "./test2.py", line 48, in <module> c.count_b() File "./test2.py", line 14, in __call__ print("Counting with:", args[0].name) IndexError: tuple index out of range 
0

1 Answer 1

2

It's a known problem (see here). I actually ran into this same issue when implementing a class decorator in one of my projects a while back.

To fix, I added the below method to my class - which you can also add to your DecoratorClass, and then it should all work without surprises.

def __get__(self, instance, owner): """ Fix: make our decorator class a decorator, so that it also works to decorate instance methods. https://stackoverflow.com/a/30105234/10237506 """ from functools import partial return partial(self.__call__, instance) 

Also, do see the linked SO answer for an example of why this is.

Sign up to request clarification or add additional context in comments.

2 Comments

Oh, good find, I voted to close this as duplicate.
yes, i unfortunatley don't know if im able to do that. I would have also voted to close it as a duplicate as well.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.