У меня есть следующая ситуация в моем коде Python:
class Parent(object):
def run(self):
print "preparing for run"
self.runImpl()
print "run done"
class Child(Parent):
def runImpl(self):
print "child running"
Однако у меня есть несколько таких 'декораторов', делая различные шаги установки/разрушения прежде и после 'runImpl', и мне не нравится иметь необходимость определить run()
, runImpl()
, runImplSingleProcess()
и т.д.
Я ищу решение следующей формы:
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"
Таким образом нет почти никакой потребности в Дочернем классе для знания об этом продолжении.
Может также быть проблема со множественным наследованием. Если a Child
наследовался Parent1
и Parent2
, Я честно не знаю то, что должно быть корректным поведением.
Кто-либо знает пользу, естественную, способ выполнить это? или я насилую дизайн здесь?
Спасибо
Yonatan
Инвертировать ваш дизайн. Вместо реализации родительской дочерней связи, которая представляет собой отношения «IS-A», почему бы не просто иметь состав, поэтому вы получаете отношения «есть»? Вы можете определить классы, которые реализуют методы, которые вы хотели бы, когда ваш предыдущий родительский класс будет создан с помощью этих конкретных классов реализации.
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, ваш вопрос не ясен! В зависимости от ситуации вы можете использовать много разных конструкций.
Одним из растворов будет иметь явную настройку () и методы rundown (), которые вызываются методом Run () перед вызовом runimpl (). Это позволит подклассам обернуть / переопределять их по мере необходимости.
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()
Однако вы упомянули многократное наследование, что означает, что это не то направление, которое вы должны принимать вообще.
Ваша упоминание нескольких наследований и упаковки (как в «декораторах») ведет меня догадаться, что вы хотите иметь возможность писать разные реализации «бегунов», каждый из которых со своей собственной процессом настройки / разрыва, во время повторного использования предметов настройки / разрыв между различными «бегунами».
Если это так, вы можете определить ресурсы, которые знают, как настроить себя и разрыть себя, и у каждого бегуна будет объявлено, какие ресурсы это требует. Метод RUN () будет выполнять соответствующую настройку / разрывное код каждого ресурса и сделать их доступными для метода RunIMPL ().
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(...)