python父类'包装'的孩子

我的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"

通过这种方式,Child类几乎不需要意识到这一点。

多重继承也可能存在问题。 如果一个Child继承Parent1Parent2 ,我真的不知道应该是什么正确的行为。

有没有人知道一个很好的,自然的方式来完成这个? 还是我在这里强奸设计?

谢谢
Yonatan


不要在这里使用继承

颠倒你的设计。 为什么不只是有一个组合,所以你得到一个“有一个”的关系,而不是一个“是 - 一个”关系的亲子实现? 您可以定义实现您想要的方法的类,而您的上一个父类将使用那些实现特定的类来实例化。

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,你的问题不清楚! 根据情况,您可以使用许多不同的设计。

一种解决方案是在调用runImpl()之前有显式的setup()和teardown()方法,这些方法由run()方法调用。 这将允许子类根据需要来包装/覆盖这些。

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

但是,您提到了多重继承,这意味着这不是您应该采取的方向。

你提到的多重继承和包装(如“装饰器”)让我猜测你希望能够编写不同的“runner”实现,每个实现都有其自己的设置/拆卸过程,同时重新使用之间的setup / 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(...)

你可以得到这个:

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)

链接地址: http://www.djcxy.com/p/44151.html

上一篇: python parent class 'wrapping' child

下一篇: MSTest Test Context Exception Handling