vlambda博客
学习文章列表

python之协议到抽象基类3

#抽象基类是用于封装框架引入的一般性概念和抽象的,定义抽象基类的子类,先利用现有的抽象基类(collections.MutableSequence),然后自己定义。我们明确把FrenchDeck2 声明为collections.MutableSequence 的子类。

#frenchdeck2.pyFrenchDeck2collections.MutableSequence 的子类

import collections

Card = collections.namedtuple('Card', ['rank''suit'])

 

class FrenchDeck2(collections.abc.MutableSequence):

    ranks = [str(n) for n in range(211)] + list('JQKA')

    suits = 'spades diamonds clubs hearts'.split()

 

    def __init__(self):

        self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]

 

    def __len__(self):

        return len(self._cards)

 

    def __getitem__(selfposition):

        return self._cards[position]

 

    def __setitem__(selfpositionvalue): 为了支持洗牌,只需实现__setitem__ 方法。

        self._cards[position] = value

 

    def __delitem__(selfposition): 但是继承MutableSequence 的类必须实现__delitem__ 方法,这是MutableSequence 类的一个抽象方法。

        del self._cards[position]

 

    def insert(selfpositionvalue): 此外,还要实现insert 方法,这是MutableSequence 类的第三个抽象方法。

        self._cards.insert(position, value)

#导入时(加载并编译frenchdeck2.py 模块时),Python 不会检查抽象方法的实现,在运行时实例化FrenchDeck2 类时才会真正检查。因此,如果没有正确实现某个抽象方法,Python 会抛出TypeError 异常,并把错误消息设为"Can't instantiate abstract class FrenchDeck2with abstract methods __delitem__, insert"。正是这个原因,即便FrenchDeck2 类不需要__delitem__ insert 提供的行为,也要实现,因为MutableSequence 抽象基类需要它们。

#MutableSequence 抽象基类和collections.abc 中它的超类的UML 类图(箭头由子类指向祖先;以斜体显示的名称是抽象类和抽象方法)


#collections.abc模块中的抽象基类;标准库中有两个名为abc 的模块,这里说的是collections.abc。在collections 包之外实现这个模块(在Lib/_collections_abc.py ),因此要与collections 分开导入。另一个abc 模块就是abc(即Lib/abc.py),这里定义的是abc.ABC 类。每个抽象基类都依赖这个类,但是不用导入它,除非定义新抽象基类。

#collections.abc 模块中定义了16 个抽象基类,简要的UML 类图(没有属性名称)。collections.abc 的官方文档中有个不错的表格(https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes),对各个抽象基类做了总结,说明了相互之间的关系,以及各个基类提供的抽象方法和具体方法(称为混入方法)。

#IterableContainer Sized各个集合应该继承这三个抽象基类,或者至少实现兼容的协议。Iterable 通过__iter__方法支持迭代,Container 通过__contains__ 方法支持in 运算符,Sized 通过__len__方法支持len() 函数。

#SequenceMapping Set这三个是主要的不可变集合类型,而且各自都有可变的子类。MutableSequence MutableMapping MutableSet 

#MappingView,在Python 3 中,映射方法.items().keys() .values() 返回的对象分别是ItemsViewKeysView ValuesView 的实例。前两个类还从Set 类继承了丰富的接口,所述的全部运算符。

#Callable Hashable这两个抽象基类与集合没有太大的关系,只不过因为collections.abc 是标准库中定义抽象基类的第一个模块,而它们又太重要了,因此才把它们放到collections.abc 模块中。我从未见过Callable Hashable 的子类。这两个抽象基类的主要作用是为内置函数isinstance 提供支持,以一种安全的方式判断对象能不能调用或散列。

#Iterator注意它是Iterable 的子类。collections.abc 之后,标准库中最有用的抽象基类包是numbers