Python parent class 'wrapping' Kind-Klasse Methoden

Ich habe folgende Situation in meinem 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" 

Allerdings habe ich mehrere solche "Dekorateure" und mache verschiedene Setup- / Teardown-Schritte vor und nach 'runImpl', und ich mag es nicht, run() , runImpl() , runImplSingleProcess() etc. zu definieren.

Ich suche eine Lösung des folgenden Formulars:

 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" 

Auf diese Weise gibt es fast keine Notwendigkeit für die Kinderklasse, sich dessen bewusst zu sein.

Es kann auch ein Problem mit Mehrfachvererbung geben. Wenn ein Child von Parent1 und Parent2 erbt, Parent1 ich ehrlich nicht, was das richtige Verhalten sein sollte.

Kennt jemand eine gute, natürliche Art und Weise, dies zu erreichen? Oder vergewaltige ich das Design hier?

Vielen Dank
Yonatan

3 Solutions collect form web for “Python parent class 'wrapping' Kind-Klasse Methoden”

Verwenden Sie hier keine Vererbung

Umkehren Sie Ihr Design. Statt einer Eltern-Kind-Implementierung, die eine "is-a" Beziehung ist, warum nicht nur eine Komposition haben, so bekommst du eine "has-a" Beziehung? Sie können Klassen definieren, die die Methoden implementieren, die Sie möchten, während Ihre vorherige übergeordnete Klasse mit diesen implementierungsspezifischen Klassen instanziiert werden würde.

 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): 

Yonatan, deine Frage ist nicht klar! Abhängig von der Situation können Sie viele verschiedene Designs verwenden.

Eine Lösung wäre, explizite setup () und teardown () Methoden zu haben, die von der run () Methode aufgerufen werden, bevor runImpl () aufgerufen wird. Dies würde es erlauben, dass Unterklassen diese nach Bedarf einpacken / überschreiben.

 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() 

Allerdings hast du mehrere Vererbung erwähnt, was bedeutet, dass dies nicht die Richtung ist, die du überhaupt nehmen solltest.

Ihre Erwähnung von mehrfacher Vererbung und Verpackung (wie in "Dekorateuren") führt mich zu erraten, dass Sie in der Lage sein werden, verschiedene "Läufer" -Entwicklungen zu schreiben, jeweils mit einem eigenen Setup / Teardown-Prozess, während Wiederverwendung von Stücke von Setup / Teardown zwischen Verschiedene "Läufer".

Wenn dies der Fall ist, können Sie Ressourcen definieren, die wissen, wie man sich einrichtet und sich selbst abnimmt, und jeder Läufer würde erklären, welche Ressourcen er benötigt. Die run () -Methode würde den entsprechenden Setup- / Teardown-Code jeder Ressource ausführen und sie der runImpl () -Methode zur Verfügung stellen.

 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(...) 

Sie können das bekommen:

 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" 

Mit:

 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 

(Nur Python 2)

  • PHP-Äquivalent für einen Python-Dekorator?
  • Wie kann ich alle aus einer Datei importierten Funktionen verzieren?
  • Verlängere Python mit C, Rückkehr numpy Array gibt Müll
  • Java Wrapper auf Perl / Python Code
  • Wie gefälschte Art mit Python
  • Python: wickle alle Funktionen in einer Bibliothek ein
  • General Dekorateur zu wrap versuchen außer in Python?
  • Bringe eine Struktur zu Python von C ++ mit BOOST.python zurück
  • Zusätzlicher Parameter für Django Modelle
  • Cython cdef Klasse nicht anzeigen doc string oder __init__ Parameter
  • Making Dekorateure mit optionalen Argumenten
  • Python ist die beste Programmiersprache der Welt.