python父类'包装'子类方法

时间:2010-01-14 15:19:38

标签: python inheritance implementation decorator wrapper

我的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" 继承自ChildParent1,我真的不知道应该采取什么样的正确行为。

有没有人知道一种良好,自然的方式来实现这一目标?或者我在这里强调设计?

感谢
Yonatan

3 个答案:

答案 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)