如果某个类扩展了abc类(抽象基类),那么除非我定义所有抽象方法,否则我无法实例化它。但是通常在实现Decorator模式时,我只想定义一些抽象方法,而其他方法 - 只需委托装饰对象。怎么做?
例如,我想让以下代码工作:
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'
而不是
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'
为此,我需要从上面的例子中实现delegate
方法。怎么实现呢?还可以考虑为扩展abc类的类提供自动委派的一些其他方法。
P.S。
请不要在此建议继承(class MyElement(StandardElement)
)作为解决方案......上面提供的代码只是一个示例。在我的实际案例中,与StandardElement相比,MyElement是完全不同的。尽管如此,我还是要让MyElement与StandardElement兼容,因为有时人们应该使用MyElement而不是StandardElement。我真的需要实施"有一个"这里的关系,而不是"是"。
答案 0 :(得分:3)
默认情况下,没有自动方法可以执行所需的委派。委托并不是抽象类的明确部分,所以这不应该是一个惊喜。但是,您可以编写自己的委托元类,为您添加缺少的方法:
def _make_delegator_method(name):
def delegator(self, *args, **kwargs):
return getattr(self._delegate, name)(*args, **kwargs)
return delegator
class DelegatingMeta(ABCMeta):
def __new__(meta, name, bases, dct):
abstract_method_names = frozenset.union(*(base.__abstractmethods__
for base in bases))
for name in abstract_method_names:
if name not in dct:
dct[name] = _make_delegator_method(name)
return super(DelegatingMeta, meta).__new__(meta, name, bases, dct)
委托方法是在一个单独的函数中生成的,因为我们需要一个名称空间,其中name
在创建函数后不会改变。在Python 3中,您可以在__new__
方法中执行所有操作,方法是为delegator
提供一个仅带有默认值的关键字参数,但Python 2中没有关键字唯一参数,因此不会为你工作。
以下是您使用它的方式:
class MyElement(IElement):
__metaclass__ = DelegatingMeta
def __init__(self, standard_element):
self._delegate = standard_element
def click(self):
return "my click"
分配给self._delegate
设置元类创建的方法将使用的对象。如果你愿意,你可以做出某种方法,但这似乎是最简单的方法。
答案 1 :(得分:0)
您收到此错误,因为类<!DOCTYPE html>
<html>
<title>Lets See</title>
<link href="https://fonts.googleapis.com/css?family=Josefin+Sans" rel="stylesheet">
<style>
h1 {
font-family: cursive;
}
button {
font-family: josefin sans;
font-size: 30px;
border-radius: 10px;
background-color: red;
color: white;
}
input {
font-family: josefin sans;
font-size: 25px;
}
</style>
<body>
<input id="txtJob" type="text" name="txtJob"> & <input type="text" id="twoPpl" name="twoPpl"> <br><br>
<button onclick="myFunction()">Test</button>
<h1 id="people" name="people" style="float: right;"></h1><br><br><h1 style="float: right;">%</h1><h1 style="float: right;" id="demo"></h1>
<script>
function myFunction() {
var jobValue = document.getElementById('txtJob').value
var twoPeople = document.getElementById('twoPpl').value
var skip = " & ";
var newVar = jobValue + skip;
var finVar = newVar + twoPeople;
var x = document.getElementById("demo")
var y = document.getElementById("name");
x.innerHTML = Math.floor((Math.random() * 100) + 1);
document.getElementById('people').innerHTML = finVar;
}
</script>
</body>
</html>
是抽象的(您没有覆盖方法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()
委托许多方法,那么__getattr__
似乎是不可能的,因为abc.abstractmethod
动态搜索必要的方法,如果没有直接运行,就无法检查__getattr__
。
因此,我建议您将所有方法指定为抽象(通过__getattr__
),这些方法肯定会在每个继承的类中被覆盖,并使用@abstractmethod
实现委托方法。一个例子:
NotImplementedError
答案 2 :(得分:0)
基于Blckknght的回答,我创建了一个python包,并扩展了多个委托人选项和自定义委托人属性名称的功能。
在这里https://github.com/monomonedula/abc-delegation
查看安装:pip install abc-delegation