在框架中,我经常想提供框架用户子类的基类.基类提供对基类的受控访问.实现此目的的一种方法是为未实现的方法提供不同的名称,例如通过添加下划线作为前缀:
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处理程序链.