Python: decorating a class method that must be overwritten by inheritance

Let's say I have a base class:

class Task: def run(self): #override this! 

Now I want other subclasses of Task to override the run () method:

 class MyTask(Task): def run(self): #successful override! 

However, the problem is that there is logic that must take place before and after the run () method for each class that subclasses Task.

It seems like one way to do this is to define another method in the base class, which then calls the run () method. However, I wanted to ask if there is a way to achieve this using decorators? What would be the most pythonic way to do this?

+4
source share
1 answer

As suggested in the comments, letting subclasses override the hook instead of run itself is probably better:

 class Task(object): def run(self): # before self.do_run() # after class MyTask(Task): def do_run(self): ... task = MyTask() task.run() 

However, this is one way to do this using the class decorator:

 def decorate_run(cls): run = getattr(cls, 'run') def new_run(self): print('before') run(self) print('after') setattr(cls, 'run', new_run) return cls class Task(object): pass @decorate_run class MyTask(Task): def run(self): pass task = MyTask() task.run() # prints: # before # after 

Another way would be to use a metaclass. The advantage of using a metaclass would be that subclasses did not need to be decorated. Task could be made an instance of a metaclass, and then all subclasses of Task inherit the metaclass automatically.

 class MetaTask(type): def __init__(cls, name, bases, clsdict): if 'run' in clsdict: def new_run(self): print('before') clsdict['run'](self) print('after') setattr(cls, 'run', new_run) class Task(object, metaclass=MetaTask): # For Python2: remove metaclass=MetaTask above and uncomment below: # __metaclass__ = MetaTask pass class MyTask(Task): def run(self): #successful override! pass task = MyTask() task.run() 
+6
source

Source: https://habr.com/ru/post/1502674/


All Articles