Python parent class 'wrapping' child class methods

I have the following situation in my Python code:

class Parent(object): def run(self): print "preparing for run" self.runImpl() print "run done" class Child(Parent): def runImpl(self): print "child running" 

However, I have several such "decorators" that perform different configuration / detach steps before and after "runImpl", and I do not like to define run() , runImpl() , runImplSingleProcess() , etc.

I am looking for a solution of the following form:

 class Parent(object): @wrapping_child_call def run(self, func_impl, *args, **kwargs) print "preparing for run" func_impl(*args, **kwargs) print "run done" class Child(Parent): def run(self): print "child running" 

Thus, for the Child class, you hardly need to know about this.

Multiple inheritance issues may also occur. If a Child inherits from Parent1 and Parent2 , I honestly don't know how the correct behavior should be.

Does anyone know a good, natural way to do this? or did i rap the design here?

thanks
Jonathan

+7
python inheritance decorator implementation wrapper
source share
3 answers

Do not use inheritance here

Invert your design. Instead of implementing a parent-child, which is an "is-a" relationship, why not just create a composition so that you get a "has-a" relationship? You can define classes that implement the methods you would like while your previous parent class was created with these implementation-specific classes.

 class MyClass: def __init__(self, impl) self.impl = impl def run(self,var): print "prepare" impl.runImpl(var) print "I'm done" class AnImplementation: def runImpl(self,var): 
+2
source share

Yonatan, your question is incomprehensible! You can use many different designs depending on the situation.

One solution would be to have explicit setup () and teardown () methods that are called by the run () method before calling runImpl (). This will allow subclasses to wrap / redefine them as needed.

 class Runner(object): def run(self): self.setup() self.runImpl() self.teardown() def setup(self): pass def teardown(self): pass class RunnerImplementation(Runner): def runImpl(self): pass # do some stuff def setup(self): print "doing setup" super(RunnerImplementation, self).setup() def teardown(self): print "doing teardown" super(RunnerImplementation, self).teardown() 

However, you mentioned multiple inheritance, which means that this is not the direction that you should take at all.

Your mention of multiple inheritance and wrapping (as in "decorators") leads me to the assumption that you want to be able to write different implementations of "runners", each of which has its own installation / break process, when reusing configuration parts / breaks between different "runners."

If so, you can identify resources that know how to tune and tear themselves apart, and each runner will announce what resources it requires. The run () method runs the corresponding install / break code for each resource and makes them available to the runImpl () method.

 class Resource(object): name = None # must give a name! def setup(self): pass def teardown(self): pass class DatabaseResource(Resource): name = "DB" def setup(self): self.db = createDatabaseConnection() def teardown(self): self.db.close() class TracingResource(Resource): name = "tracing" def setup(self): print "doing setup" def teardown(self): print "doing teardown" class Runner(object): RESOURCES = [] def run(self): resources = {} for resource_class in self.RESOURCES: resource = resource_class() resource.setup() resources[resource_class.name] = resource self.runImpl(resources) # teardown in opposite order of setup for resource in reversed(resources): resource.teardown() class RunnerA(Runner): RESOURCES = [TracingResource, DatabaseResource] def runImpl(self, resources): resources['DB'].execute(...) 
+1
source share

You can get the following:

 class Parent(object): def run(self, func_impl, *args, **kwargs): print "preparing for run" func_impl(*args, **kwargs) print "run done" class Child(Parent): @wrapped_in_parent_call def run(self): print "child running" 

FROM

 import functools class wrapped_in_parent_call(object): def __init__(self, func): self.func = func def __get__(self, obj, type=None): @functools.wraps(self.func) def wrapped(*args, **kwargs): owning_class = self.func.__get__(obj, type).im_class parent_func = getattr(super(owning_class, obj), self.func.__name__) return parent_func( lambda *a, **kw: self.func(obj, *a, **kw), *args, **kwargs ) return wrapped 

(Python 2 only)

+1
source share

All Articles