You are trying to call the instance method, logger_steps
, directly from the class StepStatusManager
, and Python is taking the value "GET_LIST"
as the self
parameter instead of type
. You should create an instance of StepStatusManager
and then make the decorator calling the method of the instance instead. It can be as simple as:
manager = StepStatusManager()
class Test:
@manager.logger_steps("GET_LIST")
def get_mails(self):
print("GET_MAIL")
This is now creating an instance of the class and then calling the method on the instance, instead of trying to call the method directly from the class. You can now use manager
to decorate as many methods as you want. Also, this would make all decorated methods use the same StepStatusManager
, but if you want you can create different instances and use them to decorate different methods; that would allow you to use different self.db
for different methods, if you need it.
Another approach could be having the db
variable in the class, and make logger_steps
a class method instead:
class StepStatusManager:
db = DB()
@classmethod
def logger_steps(cls, type):
def logger_steps(func):
@functools.wraps(func)
def wrapper(*args):
try:
func(*args)
cls.db.setStatus(type)
except BaseException as e:
print(e)
return wrapper
return logger_steps
class Test:
@StepStatusManager.logger_steps("GET_LIST")
def get_mails(self):
print("GET_MAIL")
Note however that this is less flexible, in that it will not allow you to have methods decorated with different managers, should you ever need to. Also, this is mostly equivalent to have, instead of a class, a StepStatusManager
module, where db
is a module variable and logger_steps
is a module function, and that would probably clearer if you want this functionality:
# StepStatusManager.py
# ...
db = DB()
def logger_steps(type):
def logger_steps(func):
@functools.wraps(func)
def wrapper(*args):
try:
func(*args)
cls.db.setStatus(type)
except BaseException as e:
print(e)
return wrapper
return logger_steps
# test.py
import StepStatusManager
class Test:
@StepStatusManager.logger_steps("GET_LIST")
def get_mails(self):
print("GET_MAIL")
Again this is maybe more straightforward but less flexible as your first proposed class-based solution.
EDIT:
Just for completeness and comparison, here is yet another version, similar to the one with @classmethod
, but using @staticmethod
instead (to understand the subtle difference between these two decorators, check one of the many SO questions about it, e.g. What is the difference between @staticmethod and @classmethod? or Meaning of @classmethod and @staticmethod for beginner?):
class StepStatusManager:
db = DB()
@staticmethod
def logger_steps(type):
def logger_steps(func):
@functools.wraps(func)
def wrapper(*args):
try:
func(*args)
StepStatusManager.db.setStatus(type)
except BaseException as e:
print(e)
return wrapper
return logger_steps
class Test:
@StepStatusManager.logger_steps("GET_LIST")
def get_mails(self):
print("GET_MAIL")
As it frequently happens with @classmethod
and @staticmethod
, the difference is quite minimal. Their behavior might differ if you are using inheritance, or if you are using a metaclass, or a decorator, or something like that, but otherwise they pretty much the same.