9

我的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()ParentChildChildSingleProcess

我正在寻找以下形式的解决方案:

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 类几乎不需要意识到这一点。

多重继承也可能存在问题。如果 aChild继承自Parent1and Parent2,老实说,我不知道正确的行为应该是什么。

有谁知道一个好的,自然的,实现这一点的方法?还是我在这里强奸设计?

谢谢
Yonatan

4

3 回答 3

3

不要在这里使用继承

反转你的设计。而不是一个“is-a”关系的父子实现,为什么不只是有一个组合,所以你得到一个“has-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):
于 2010-01-14T15:26:50.967 回答
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() 方法将运行每个资源的相关设置/拆卸代码,并使它们可用于 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(...)
于 2010-01-14T16:11:41.633 回答
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)

于 2013-05-17T15:52:06.873 回答