我的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()
,{{1等等。
我正在寻找以下形式的解决方案:
runImplSingleProcess()
通过这种方式,Child类几乎不需要意识到这一点。
多重继承可能存在问题。如果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"
继承自Child
和Parent1
,我真的不知道应该采取什么样的正确行为。
有没有人知道一种良好,自然的方式来实现这一目标?或者我在这里强调设计?
感谢
Yonatan
答案 0 :(得分:2)
反转您的设计。而不是一个“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):
答案 1 :(得分:1)
Yonatan,你的问题不明确!根据具体情况,您可以使用许多不同的设计。
一种解决方案是在调用runImpl()之前使用run()方法调用的显式setup()和teardown()方法。这将允许子类根据需要包装/覆盖它们。
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()方法将运行每个资源的相关setup / teardown代码,并使它们可用于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(...)
答案 2 :(得分:1)
你可以得到这个:
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"
使用:
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)