python 定义抽象基类子类

定义抽象基类的子类:
下面的例子:FrenchDeck2 声明为collections. MutableSequence 的子类。

import collections
from random import shuffle

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


class FrenchDeck2(collections.MutableSequence):
    ranks = [str(n) for n in range(2, 11)] + 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__(self, position):
        return self._cards[position]

    def __setitem__(self, key, value):
        self._cards[key] = value

    def __delitem__(self, position):
        del self._cards[position]

    def insert(self, position, value):
        self._cards.insert(position, value)

1,为了支持洗牌,只需实现 __setitem__ 方法。
2,但是继承 MutableSequence 的类必须实现 __delitem__ 方法,这是MutableSequence 类的 一个抽象方法。
3,此外,还要实现 insert 方法,这是 MutableSequence 类的第三个抽象方法。

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

在这里插入图片描述
FrenchDeck2 从 Sequence 继承了几个拿来即用的具体方法:__contains____iter____reversed__indexcountFrenchDeck2MutableSequence 继承了appendextendpopremove__iadd__

在 collections.abc 中,每个抽象基类的具体方法都是作为类的公开接口实现的,因此不 用知道实例的内部接口。

要想实现子类,我们可以覆盖从抽象基类中继承的方法,以更高效的方式重 新实现。例如,__contains__ 方法会全面扫描序列,可是,如果你定义的序 列按顺序保存元素,那就可以重新定义 __contains__ 方法,使用 bisect 函 数做二分找,从而提升搜索速度。

标准库中的抽象基类:
从 Python 2.6 开始,标准库提供了抽象基类。大多数抽象基类在 collections.abc 模块中定 义,不过其他地方也有。例如,numbersio 包中有一些抽象基类。但是,collections. abc 中的抽象基类最常用。我们来看看这个模块中有哪些抽象基类。

1,collections.abc模块中的抽象基类:
标准库中有两个名为 abc 的模块,这里说的是 collections.abc。为了减少加 载时间,Python 3.4 在 collections 包之外实现这个模块(在 Lib/collections abc.py 中,https://hg.python.org/cpython/file/3.4/Lib/_collections_abc.py),因此要 与 collections 分开导入。另一个abc 模块就是abc(即Lib/abc.py,https:// hg.python.org/cpython/file/3.4/Lib/abc.py),这里定义的是 abc.ABC 类。每个抽象 基类都依赖这个类,但是不用导入它,除非定义新抽象基类。

Python 3.4 在 collections.abc 模块中定义了16 个抽象基类,简要的UML 类图:
在这里插入图片描述
和官方文档中这些抽象基类的表格(https://docs.python.org/zh-cn/3.6/library/collections.abc.html):
在这里插入图片描述
这里来细说这些抽象基类:
Iterable、Container 和 Sized
各个集合应该继承这三个抽象基类,或者至少实现兼容的协议。Iterable 通过 __iter__ 方法支持迭代,Container 通过 __contains__ 方法支持 in 运算符,Sized 通过 __len__ 方法支持 len() 函数。

Sequence、Mapping 和 Set
这三个是主要的不可变集合类型,而且各自都有可变的子类。MutableSequence 的详细 类图见图 如下;MutableMappingMutableSet 的类图如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
MappingView
在 Python 3 中,映射方法 .items().keys().values() 返回的对象分别是 ItemsViewKeysViewValuesView 的实例。前两个类还从 Set 类继承了丰富的接口,包含 如下的全部运算符:
在这里插入图片描述
在这里插入图片描述
Callable 和 Hashable
这两个抽象基类与集合没有太大的关系,只不过因为 collections.abc 是标准库中定义 抽象基类的第一个模块,而它们又太重要了,因此才把它们放到 collections.abc 模块 中。我从未见过 CallableHashable 的子类。这两个抽象基类的主要作用是为内置函 数 isinstance 提供支持,以一种安全的方式判断对象能不能调用或散列。

若想检查是否能调用,可以使用内置的 callable() 函数;但是没有类似的 hashable() 函数,因此测 试对象是否可散列,最好使用 isinstance(my_obj, Hashable)。

2、numbers 包中的抽象基类:
numbers 包 定义的是“数字塔”(即各个抽 象基类的层次结构是线性的),其中 Number 是位于最顶端的超类,随后是 Complex 子类, 依次往下,最底端是 Integral 类:
在这里插入图片描述
因此,如果想检查一个数是不是整数,可以使用 isinstance(x, numbers.Integral),这样 代码就能接受 int、bool(int 的子类),或者外部库使用 numbers 抽象基类注册的其他类 型。为了满足检查的需要,你或者你的 API 的用户始终可以把兼容的类型注册为 numbers. Integral 的虚拟子类。

与之类似,如果一个值可能是浮点数类型,可以使用 isinstance(x, numbers.Real) 检查。 这样代码就能接受 bool、int、float、fractions.Fraction,或者外部库(如 NumPy,它 做了相应的注册)提供的非复数类型。

decimal.Decimal 没有注册为 numbers.Real 的虚拟子类,这有点奇怪。没注 册的原因是,如果你的程序需要 Decimal 的精度,要防止与其他低精度数字 类型混淆,尤其是浮点数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值