如果某个类扩展了 abc 类(抽象基类),那么除非我定义所有抽象方法,否则我无法实例化它。但通常在实现装饰器模式时,我只想定义一些抽象方法,而其他方法则仅委托给装饰对象。这个怎么做?
例如,我想让下面的代码工作:
from abc import ABCMeta, abstractmethod
class IElement(object):
__metaclass__ = ABCMeta
@abstractmethod
def click(self):
return
@abstractmethod
def hover(self):
return
# ... more IElement's abstractmethods...
class StandardElement(IElement):
def click(self):
return "click"
def hover(self):
return "hover"
# ... more implemented IElement's methods...
class MyElement(IElement):
def __init__(self, standard_element):
self._standard_element = standard_element
delegate(IElement, standard_element)
def click(self):
return "my click"
assert MyElement(StandardElement()).click() == 'my click'
assert MyElement(StandardElement()).hover() == 'click'
Run Code Online (Sandbox Code Playgroud)
代替
from abc import ABCMeta, abstractmethod
class IElement(object):
__metaclass__ = ABCMeta
@abstractmethod
def click(self):
return
@abstractmethod
def hover(self):
return
# ... more IElement's abstractmethods...
class StandardElement(IElement):
def click(self):
return "click"
def hover(self):
return "hover"
# ... more implemented IElement's methods...
class MyElement(IElement):
def __init__(self, standard_element):
self._standard_element = standard_element
def click(self):
return "my click"
def hover(self):
return self._standard_element.hover()
# ... more manually delegated IElement's methods to self._standard_element object, aggregated in initialiser...
assert MyElement(StandardElement()).click() == 'my click'
assert MyElement(StandardElement()).hover() == 'click'
Run Code Online (Sandbox Code Playgroud)
为此,我需要实现delegate
上面示例中的方法。如何实施?也可以考虑为扩展 abc 类的类提供自动委托的一些其他方法。
PS 请不要class MyElement(StandardElement)
在这里建议我使用继承()作为解决方案...上面提供的代码只是一个示例。在我的真实案例中,MyElement 与 StandardElement 相比有很大不同。不过,我必须使 MyElement 与 StandardElement 兼容,因为有时应该有人使用 MyElement 而不是 StandardElement。我真的需要在这里实现“有一个”关系,而不是“是一个”。
您收到此错误是因为该类MyElement
是抽象的(您尚未重写该方法hover
)。抽象类是至少具有一个抽象方法的类。为了解决该错误,您应该以这种方式添加此方法,例如:
class MyElement(IElement):
def __init__(self, standard_element):
self._standard_element = standard_element
def click(self):
return "my click"
def hover(self):
return self._standard_element.hover()
Run Code Online (Sandbox Code Playgroud)
如果您想使用__getattr__
via 来委托许多方法似乎是不可能的abc.abstractmethod
,因为__getattr__
动态搜索必要的方法,而如果不直接运行__getattr__
.
因此,我建议您将所有方法指定为抽象方法(通过@abstractmethod
),这些方法肯定会在每个继承类中被重写,并使用 实现委托方法NotImplementedError
。一个例子:
class IElement(object):
__metaclass__ = ABCMeta
@abstractmethod
def necessary_to_implement_explicitely(self):
pass
def click(self):
raise NotImplementedError()
def hover(self):
raise NotImplementedError()
Run Code Online (Sandbox Code Playgroud)