第十一章 - 接口:从协议到抽象基类

接口:从协议到抽象基类

猴子补丁:在运行时修改类或模块而不修改源码

对于Python来说: 协议 == 接口

ABC = Abstract Base Class

抽象类表示接口 —— Bjarne C++之父

抽象基类、描述符和元类都是用于构建框架的工具,因此只有少数Python开发者编写的抽象基类不会对用户施加不必需要的限制,让他们做无用功。

 

11.2 Python喜欢序列

class Foo(object):
    def __getitem__(self, item):
        return range(0, 5)[item]

f = Foo()
print(f[1])

for i in f:
    print(i)

>>>
1
0
1
2
3
4

 

11.6 标准库中的抽象基类

Python从2.6开始,标准库提供了抽象基类,大多数抽象基类在collecitons.abc模块中定义。

 

11.7 定义并使用一个抽象基类

 示例11-7

import abc

class Tombola(abc.ABC):
    
    @abc.abstractmethod
    def load(self, iterable):
        """从可迭代对象中添加元素"""
        
    @abc.abstractmethod
    def pick(self):
        """随机删除元素,然后将其返回
        如果实例为空,这个方法应该抛出'LookupError'"""
    
    def loaded(self):
        """如果至少有一个元素,返回True,否则返回False"""
        return bool(self.inspect())
        
    def inspect(self):
        """返回一个有序元组,由当前元素构成。"""
        items = []
        while True:
            try:
                items.append(self.pick())
            except LookupError:
                break
        self.load(items)
        return tuple(sorted(items))

注意: 其实抽象方法可以有实现代码,即便实现了,子类也必须覆盖抽象方法,但是在子类中可以使用super()函数调用父类的抽象方法,为它添加功能,而不是从头开始实现。

import random
from abstract import Tombola

class BingoCage(Tombola):
    def __init__(self, items):
        self._randomizer = random.SystemRandom()
        self._items = []
        self.load(items)

    def load(self, iterable):
        self._items.extend(iterable)
        self._randomizer.shuffle(self._items)

    def pick(self):
        try:
            return self._items.pop()
        except IndexError:
            raise LookupError("pick from empty BingoCage")

    def __call__(self, *args, **kwargs):
        self.pick()

 

posted @ 2017-07-26 22:44  Vincen_shen  阅读(192)  评论(0)    收藏  举报