Reputation: 2025
I have a decorator that performs a couple of logging operations,
def event_logger(function):
def wrapper(*args, **kwargs):
# get the logger
logger = logging.getLogger()
logger.info("Some log")
# execute the function
return_value = function(*args, **kwargs)
logger.info("Some log")
return return_value
return wrapper
Now, I have implemented a bunch of processors
that each inherit from an interface (Factory Pattern).
My interface looks like this,
class IProcessor(ABC):
@property
def _logger(self):
return logging.getLogger(__name__)
@abstractmethod
def process(self):
"""
Execute processing operation
"""
raise NotImplementedError("Subclasses must implement process method")
An example of a processor (subclass) would look like this,
class TestProcessor(IProcessor):
@event_logger
def process(self):
self._logger.info("TestPreProcessor")
As shown here, the @event_logger
decorator has been added to the process
method of my subclass. This works, but it would mean that each time I have a new processor
, I would need to remember to add the decorator.
Is there anyway I can avoid this maybe by adding the decorator to the process
method of the interface or something? I know this will probably not work, since the subclass will be overwriting this method though. Is there some way that I can achieve this?
Upvotes: 0
Views: 49
Reputation: 110271
You can add the decorator in the __init_subclass__
method of your interface class.
If the methods to be decorated are always "final": that is, they don't call the super()
version of themselves, it is easy to do. If they do call their super-versions, which could also be decorated - then you have to add some state-checking logic to avoid performing the decorator code more than once (that may be tricky)
class IProcessor(ABC):
_methods_to_add_logging = ("process", )
def __init_subclass__(cls, *args, **kw):
super().__init_subclass__(*args, **kw)
for method_name in __class__._methods_to_add_logging:
method = getattr(cls, method_name, None)
if not method:
continue
method = event_logger(method)
setattr(cls, method_name, method)
@property
def _logger(self):
return logging.getLogger(__name__)
@abstractmethod
def process(self):
"""
Execute processing operation
"""
raise NotImplementedError("Subclasses must implement process method")
Upvotes: 1