抽象类和接口定义
项目描述
抽象类和接口定义。
创建一个 abstract.Abstraction
Abstraction 是定义抽象类的元类。
让我们定义一个抽象类 AFoo 并给它一个抽象方法 do_foo。
与任何Python类一样,Abstraction 可以有任意的名字,但通过在名称前缀加上 A 可能有助于区分抽象类和其他类。
>>> import abc
>>> import abstracts
>>> class AFoo(metaclass=abstracts.Abstraction):
...
... @abc.abstractmethod
... def do_foo(self):
... raise NotImplementedError
抽象类 不能 被直接实例化。
>>> AFoo()
Traceback (most recent call last):
...
TypeError: Can't instantiate abstract class AFoo with abstract method... do_foo
为 abstract.Abstraction 创建一个实现者
为了使用 AFoo,我们需要为它创建一个实现者。
>>> @abstracts.implementer(AFoo)
... class Foo:
... pass
实现者 必须 实现其抽象类定义的所有抽象方法。
>>> Foo()
Traceback (most recent call last):
...
TypeError: Can't instantiate abstract class Foo with abstract method... do_foo
>>> @abstracts.implementer(AFoo)
... class Foo2:
...
... def do_foo(self):
... return "DID FOO"
>>> Foo2()
<__main__.Foo2 object at ...>
实现者继承自其 Abstractions
实现者类是其 Abstraction 的子类。
>>> issubclass(Foo2, AFoo)
True
同样,实现者实例是其 Abstraction 的实例
>>> isinstance(Foo2(), AFoo)
True
Abstraction 类可以在类 bases 中看到,并且实现者可以调用 Abstraction 的方法。
>>> import inspect
>>> AFoo in inspect.getmro(Foo2)
True
创建一个实现多个抽象的实现者。
实现者可以实现多个抽象。
让我们创建第二个抽象。
>>> class ABar(metaclass=abstracts.Abstraction):
...
... @abc.abstractmethod
... def do_bar(self):
... raise NotImplementedError
现在我们可以创建一个实现者,它同时实现AFoo和ABar的抽象。
>>> @abstracts.implementer((AFoo, ABar))
... class FooBar:
...
... def do_foo(self):
... return "DID FOO"
...
... def do_bar(self):
... return "DID BAR"
>>> FooBar()
<__main__.FooBar object at ...>
定义抽象属性
属性可以在抽象类中定义,就像普通方法一样,任何实现者都必须实现它们。
>>> class AMover(metaclass=abstracts.Abstraction):
...
... @property
... @abc.abstractmethod
... def speed(self):
... return 5
...
... @property
... @abc.abstractmethod
... def direction(self):
... return "forwards"
在abstractmethod中调用super()
就像Python的“抽象基类”一样,你可以在abstractmethod中调用super()来调用抽象实现。
>>> @abstracts.implementer(AMover)
... class Mover:
...
... @property
... def direction(self):
... return "backwards"
...
... @property
... def speed(self):
... return super().speed
这个自定义的AMover实现必须实现speed和direction,即使它的实现调用了抽象实现。
在这种情况下,它使用了默认/抽象的speed实现,同时提供了它自己的direction实现。
>>> mover = Mover()
>>> mover
<__main__.Mover object at ...>
>>> mover.speed
5
>>> mover.direction
'backwards'
定义abstracts.Interface类
Interface与抽象类似,但有一些区别。
Interface只能使用@interfacemethod装饰器定义方法。
它不能定义普通方法或带有@abstractmethod的方法,只能定义带有@interfacemethod的方法。
如果调用@interfacemethod,将始终引发一个NotImplementedError,因此不能用作抽象实现。
让我们添加一个我们可以使用的Interface类。
就像区分抽象与其他类型的类可能有所帮助一样,使用I前缀命名它们也可能有助于区分Interface。
>>> class IGeared(metaclass=abstracts.Interface):
...
... @property
... @abstracts.interfacemethod
... def number_of_gears(self):
... # Raising an error is ~superfluous as the decorator will raise
... # anyway if the method is invoked.
... raise NotImplementedError
实现一个Interface
就像实现抽象一样,可以使用@implementer装饰器实现Interface。
实现者可以实现抽象和Interface的组合。
>>> @abstracts.implementer((AMover, IGeared))
... class Bicycle:
...
... @property
... def direction(self):
... return super().direction
...
... @property
... def speed(self):
... return super().speed
...
... @property
... def number_of_gears(self):
... return 7
>>> Bicycle().number_of_gears
7
实现者不从其Interface继承
实现者类是其Interface的子类。
>>> issubclass(Bicycle, AMover)
True
>>> issubclass(Bicycle, IGeared)
True
同样,实现者的一个实例是其Interface的一个实例。
>>> isinstance(Bicycle(), AMover)
True
>>> isinstance(Bicycle(), IGeared)
True
与抽象不同,它不继承自其Interface。
>>> AMover in inspect.getmro(Bicycle)
True
>>> IGeared in inspect.getmro(Bicycle)
False
@interfacemethods永远不会被调用
要记住的关键一点是,你不能在@interfacemethod上调用super()或直接调用它。
如果它在Interface中定义为部分,你将收到一个AttributeError,因为实现没有直接从接口继承。
>>> @abstracts.implementer((AMover, IGeared))
... class BrokenBicycle:
...
... @property
... def direction(self):
... return super().direction
...
... @property
... def speed(self):
... return super().speed
...
... @property
... def number_of_gears(self):
... return super().number_of_gears
>>> BrokenBicycle().number_of_gears
Traceback (most recent call last):
...
AttributeError: 'super' object has no attribute 'number_of_gears'
如果你在一个作为抽象一部分定义的@interfacemethod上调用super(),它将引发NotImplementedError。
由于Interface只能包含此类方法,因此你永远不能调用其任何方法。直接这样做将引发一个NotImplementedError。
>>> IGeared.number_of_gears.__get__(Bicycle())
Traceback (most recent call last):
...
NotImplementedError
在抽象中组合@abstractmethod和@interfacemethod
由于接口是“纯的”,因此它们不能使用@abstractmethod或包含任何实现。
另一方面,抽象可以同时结合这两者。
让我们创建一个纯接口,表示“车库”。
>>> class IShed(metaclass=abstracts.Interface):
...
... @property
... @abstracts.interfacemethod
... def size(self):
... raise NotImplementedError
我们可以使用这个接口来创建一个ABikeShed 抽象。
>>> class ABikeShed(IShed, metaclass=abstracts.Abstraction):
...
... @property
... @abstracts.interfacemethod
... def max_bike_size(self):
... raise NotImplementedError
...
... @abc.abstractmethod
... def get_capacity(self):
... return int(self.size / self.max_bike_size)
现在我们可以创建一个实现。
它需要定义size和max_bike_size,因为这些是interfacemethods。
然而,它可以利用get_capacity的抽象实现,即使它必须被定义。
>>> @abstracts.implementer(ABikeShed)
... class BikeShed:
...
... @property
... def max_bike_size(self):
... return 7
...
... @property
... def size(self):
... return 161
...
... def get_capacity(self):
... return super().get_capacity()
>>> bikeshed = BikeShed()
>>> bikeshed.get_capacity()
23
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪一个,请了解更多关于安装包的信息。
源代码发行版
构建发行版
abstracts-0.0.12-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | acc01ff56c8a05fb88150dff62e295f9071fc33388c42f1dfc2787a8d1c755ff |
|
MD5 | fe52602af3b447a9ccfcf57eedd660d3 |
|
BLAKE2b-256 | 934f158ded37e69172bba7987774885629afa9b482857edde5e87399c89e7d66 |