如何在继承树中多次包装子方法?

在框架中,我经常想提供框架用户子类的基类.基类提供对基类的受控访问.实现此目的的一种方法是为未实现的方法提供不同的名称,例如通过添加下划线作为前缀:

class Base:

    def method(self, arg):
        # ...
        result = self._method(arg)
        # ...
        return result

    def _method(self, arg):
        raise NotImplementedError

但是,此方案仅适用于一个继承级别.对于更高的级别,不同的方法名称使您难以对正在发生的事情进行概述.而且,框架用户必须根据他选择的基类重写不同的方法:

class Base:

    def method(self, arg):
        # ...
        result = self._method_sub(arg)
        # ...
        return result

    def _method_sub(self, arg):
        raise NotImplementedError

class Intermediate(Base):

    def _method_sub(self, arg):
        # ...
        result = self._method_sub_sub(arg)
        # ...
        return result

    def _method_sub_sub(self, arg):
        raise NotImplementedError

当基本方法需要访问子方法的返回值时,调用超级方法无济于事.我觉得面向对象略有缺陷,缺少一个子关键字,该关键字允许将调用转发给子类.有哪些解决方案可以解决此问题?

解决方法:

我认为问题集中在中产阶级行为扩展可能发生的不同点上.中产阶级显然应该在这里完善“控制”部分.

第一种解决方案

通常,这可以通过重写“安全”方法来以经典方式完成-尤其是在“基础和中间层都是框架提供的抽象类”时,可以将事情组织起来.
完成铲子工作的最终“傻”实现类将覆盖不安全的方法.

想想这个例子:

class DoublePositive:
    def double(self, x):
        assert x > 0
        return self._double(x)
    def _double(self, x):
        raise NotImplementedError

class DoubleIntPositive(DoublePositive):
    def double(self, x):
        assert isinstance(x, int)
        return DoublePositive.double(self, x)

class DoubleImplementation(DoubleIntPositive):
    def _double(self, x):
        return 2 * x

第二解决方案

调用虚拟子类方法,从而以非经典方式在“内部”执行点进行行为扩展,可以通过Python进行内省-通过使用辅助函数降低类__bases__或方法解析顺序__mro__来完成.

例:

def child_method(cls, meth, _scls=None):
    scls = _scls or meth.__self__.__class__
    for base in scls.__bases__:
        if base is cls:
            cmeth = getattr(scls, meth.__name__, None)
            if cmeth.__func__ is getattr(cls, meth.__name__, None).__func__:
                return child_method(scls, meth)  # next child
            if cmeth:
                return cmeth.__get__(meth.__self__)
    for base in scls.__bases__:
        r = child_method(cls, meth, base)  # next base
        if r is not None:
            return r
    if _scls is None:
        raise AttributeError("child method %r missing" % meth.__name__)    
    return None

class Base(object):
    def double(self, x):
        assert x > 0
        return Base._double(self, x)
    def _double(self, x):
        return child_method(Base, self._double)(x)        
class Inter(Base):
    def _double(self, x):
        assert isinstance(x, float)
        return child_method(Inter, self._double)(x)
class Impl(Inter):
    def _double(self, x):
        return 2.0 * x

因此,这里的辅助函数child_method()与Python的super()相反.

第三解决方案

如果调用应该是可灵活链接的,则可以将事物显式地组织为一种处理程序链.想想__init __()链中的self.addHandler(self .__ privmeth)-甚至通过棘手的元类.学习例如urllib2处理程序链.

上一篇:php-Web应用程序:从头开始编写代码还是使用3rd party框架?


下一篇:我可以在Agile Toolkit中创建带有子菜单的菜单吗?