Reputation: 19395
I am trying to apply a class decorator to each of its methods. But staticmethod
and classmethod
are not working for me. I got this:
import functools
import re
def decor(cls):
def decorator(f):
if isinstance(f, type):
for attr in f.__dict__:
if callable(getattr(f, attr)) and not re.match(r"__\w*__", attr):
setattr(f, attr, decorator(getattr(f, attr)))
return f
@functools.wraps(f)
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
return wrapper
return decorator(cls)
@decor
class MyClass:
def printer1(self, string):
print(string)
@classmethod
def printer2(cls, string):
print(string)
@staticmethod
def printer3(string):
print(string)
MyClass().printer1("foo") # this works
MyClass().printer2("foo") # this does not work
MyClass.printer2("foo") # this works
MyClass().printer3("foo") # this does not work
MyClass.printer3("foo") # this works
# the error is the following:
TypeError: printer() takes 1 positional argument but 2 were given
Basically every time I instantiate the class, I get the error when calling a staticmethod
and a classmethod
.
Upvotes: 0
Views: 272
Reputation: 7736
You don't seem to understand the working principle of staticmethod
and classmethod
. This is a link about the working principle of classmethod. The working principle of the staticmethod
is similar to that of the classmethod
. The difference is that when accessing the staticmethod
, the class will not be bound to the function, but simply return the function.
There are two problems:
staticmethod
and classmethod
from working properly.staticmethod
and classmethod
, getattr
will get the result returned after the descriptor triggers the __get__
method, not necessarily the function itself. And here you only use wrapper
to wrap, and do not restore them to the corresponding special methods.Here is a working example:
def decorator(cls_or_func):
if isinstance(cls_or_func, type):
cls = cls_or_func
for name, attr in cls.__dict__.items():
if isinstance(attr, (staticmethod, classmethod)):
setattr(cls, name, type(attr)(decorator(attr.__func__)))
elif callable(attr) and not re.match(r"__\w*__", name):
setattr(cls, name, decorator(attr))
return cls
func = cls_or_func
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
Upvotes: 1