Python抽象基类的定义与使用方法

目录
  • 1、定义抽象基类的子类
  • 2、标准库中的抽象基类
  • 3、定义抽象基类
  • 4、再看白鹅类型

前言:

我们写Python基本不需要自己创建抽象基类,而是通过鸭子类型来解决大部分问题。《流畅的Python》作者使用了15年Python,但只在项目中创建过一个抽象基类。我们更多时候是创建现有抽象基类的子类,或者使用现有的抽象基类注册。本文的意义在于,了解抽象基类的定义与使用,可以帮助我们理解抽象基类是如何实现的,为我们以后学习后端语言(比如JavaGolang)打下基础。毕竟抽象基类是编程语言通用设计。

1、定义抽象基类的子类

先回顾下什么是抽象基类:Python的抽象基类是指必须让继承它的子类去实现它所要求的抽象方法的类。如下代码定义了抽象基类collections.MutableSequence的子类:

import collections 

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, position, value):  # <1>
        self._cards[position] = value 

    def __delitem__(self, position):  # <2>
        del self._cards[position] 

    def insert(self, position, value):  # <3>
        self._cards.insert(position, value)

通过抽象基类collections.MutableSequence源码:

可以发现,它有三个抽象方法__setitem__ __delitem__ insert,所以FrenchDeck2类必须实现它们。而对于其他非抽象方法比如appendextendpop等,则可以直接继承无需实现。

注意:Python只会在运行时实例化FrenchDeck2类时真正检查抽象方法的实现,如果未实现会抛出TypeError异常,提示Can't instantiate abstract class之类的。

2、标准库中的抽象基类

为了知道哪些抽象基类可以使用,我们可以看看标准库。

collections.abc

collections.abc的抽象基类如下图所示:

Iterable、Container、Sized

这三个抽象基类是最基础的类,各个集合都继承了这三个抽象基类。

  • Itearble通过__iter__方法支持迭代
  • Container通过__contains__方法支持in运算符
  • Sized通过__len__方法支持len()函数

Sequence、Mapping、Set

不可变集合类型,各自都有可变的子类。

MappingView

.items().keys() .values()返回的对象分别是ItemsViewKeysViewValuesView的实例。

Callable、Hashable

为内置函数isinstance提供支持,判断对象能不能调用或散列。

Iterator

迭代器。

numbers

numbers的抽象基类有以下几种:

  • Number
  • Complex
  • Real
  • Rational
  • Integral

这叫做数字塔,顶部是超类,底部是子类。比如使用isinstance(x, numbers.Integral)检查一个数是不是整数,这样代码就能接受intbool(int的子类),再比如使用isinstance(x, numbers.Real)检查浮点数,这样代码就能接受boolintfloatfractions.Fraction

3、定义抽象基类

抽象基类的示例代码如下:

# BEGIN TOMBOLA_ABC 

import abc 

class Tombola(abc.ABC):  # <1> 

    @abc.abstractmethod
    def load(self, iterable):  # <2>
        """Add items from an iterable.""" 

    @abc.abstractmethod
    def pick(self):  # <3>
        """Remove item at random, returning it.
        This method should raise `LookupError` when the instance is empty.
        """ 

    def loaded(self):  # <4>
        """Return `True` if there's at least 1 item, `False` otherwise."""
        return bool(self.inspect())  # <5> 

    def inspect(self):
        """Return a sorted tuple with the items currently inside."""
        items = []
        while True:  # <6>
            try:
                items.append(self.pick())
            except LookupError:
                break
        self.load(items)  # <7>
        return tuple(sorted(items)) 

# END TOMBOLA_ABC

要点:

  • 继承abc.ABC
  • 使用@abc.abstractmethod装饰器标记抽象方法
  • 抽象基类也可以包含普通方法
  • 抽象基类的子类必须覆盖抽象方法(普通方法可以不覆盖),可以使用super()函数调用抽象方法,为它添加功能,而不是从头开始实现

4、再看白鹅类型

白鹅类型的定义有一点难以理解,如果理解了虚拟子类,就能加快理解白鹅类型。虚拟子类并不是抽象基类的真正子类,而是注册到抽象基类上的子类,这样Python就不会做强制检查了。

注册的方式有两种:

  • register方法

Python3.3以前只能使用register方法,比如collections.abc模块的源码中,把内置类型tuplestrrangememoryview注册为Sequence的虚拟子类:

    Sequence.register(tuple)
    Sequence.register(str)
    Sequence.register(range)
    Sequence.register(memoryview)
    
  • register装饰器

TomboList注册为Tombola的虚拟子类:

@Tombola.register
class TomboList(list):
    ...

白鹅类型和鸭子类型是Python的动态特性,它们的共同点是,只要长的像,Python就不会做强制检查,鸭子类型是针对普通类的子类而言的,白鹅类型是针对抽象基类的虚拟子类而言的。

参考资料:

《流畅的Python》第11章 接口:从协议到抽象基类

到此这篇关于Python抽象基类的定义与使用方法的文章就介绍到这了,更多相关Python抽象基类的定义与使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python抽象基类用法实例分析

    本文实例讲述了python抽象基类用法.分享给大家供大家参考.具体如下: 定义抽象类,需要使用abc模块,该模块定义了一个元类(ABCMeata),和装饰器 @abstractmethod, @abstractproperty 如果要实例化继承了Foo 的子类,子类必须实现了Foo所有的抽象方法(跟java一样),否则实例化报错. 抽象类不能直接实例化 #!coding=utf-8 from abc import ABCMeta, abstractmethod, abstractproperty

  • python 接口_从协议到抽象基类详解

    抽象基类的常见用途:实现接口时作为超类使用.然后,说明抽象基类如何检查具体子类是否符合接口定义,以及如何使用注册机制声明一个类实现了某个接口,而不进行子类化操作.最后,说明如何让抽象基类自动"识别"任何符合接口的类--不进行子类化或注册. Python文化中的接口和协议 接口在动态类型语言中是怎么运作的呢?首先,基本的事实是,Python语言没有 interface 关键字,而且除了抽象基类,每个类都有接口:类实现或继承的公开属性(方法或数据属性),包括特殊方法,如__getitem_

  • Python抽象基类的定义与使用方法

    目录 1.定义抽象基类的子类 2.标准库中的抽象基类 3.定义抽象基类 4.再看白鹅类型 前言: 我们写Python基本不需要自己创建抽象基类,而是通过鸭子类型来解决大部分问题.<流畅的Python>作者使用了15年Python,但只在项目中创建过一个抽象基类.我们更多时候是创建现有抽象基类的子类,或者使用现有的抽象基类注册.本文的意义在于,了解抽象基类的定义与使用,可以帮助我们理解抽象基类是如何实现的,为我们以后学习后端语言(比如Java.Golang)打下基础.毕竟抽象基类是编程语言通用设

  • Python中的类的定义和对象的创建方法

    目录 1.创建类和创建类对象 2.新式类与旧式(经典)类 面向对象中两个重要的概念: 1.类   :对一类事物的描述,是抽象的.概念上的定义.比如做石膏像的模型2.对象:实际存在的该类事物的每个个体,因而也称实例(instance).比如石膏像二者的关系:对象是由类派生的.创建的.一个类可以创建无穷多个对象,每个对象都属于类. 1.创建类和创建类对象 1.创建类,类主要由类名,属性,方法组成,当然创建一个类时,属性和方法可以选择的. class Person: def cry(self): #类

  • C++抽象基类讲解

     公众号:Coder梁(ID:Coder_LT) 这一篇文章来聊聊抽象基类(abstract base class简称ABC). 我们之前说过,在我们实现继承的时候,需要保证派生类和基类之间是一种is-a的关系.在大多数时刻,这样的关系是没有问题的,然而在一些特殊的情况可能会遇到问题. 比如说,假设我们要实现所有的图形.在图形当中,圆是一种特殊的椭圆.但椭圆包含的属性更多,椭圆除了有中心点之外,还有半长轴.半短轴,以及方向角,而圆只需要圆心和半径即可. 也就是说虽然圆是椭圆,但圆包含的属性却更少

  • Visual C#类的定义及实现方法实例解析

    本文实例演示了visual C#下一个类的定义及实现方法,虽然是一个较为基础的C#代码实例,对于新手来说仍然有很好的参考价值. 具体的实例代码如下: using System; public class Desk//基类Desk { protected int length;//保护成员 protected int width; protected int height; //类Desk的构造函数 public Desk( ) { length = 0; width = 0; height =

  • JS类的定义与使用方法深入探索

    本文实例分析了JS类的定义与使用方法.分享给大家供大家参考,具体如下: js可以定义自己的类 很有意思 <script type="text/javascript"> var Anim = function() { alert('nihao'); }; Anim.prototype.start = function() { alert('start'); }; Anim.prototype.stop = function() { alert('stop'); }; var

  • Python数据结构之双向链表的定义与使用方法示例

    本文实例讲述了Python数据结构之双向链表的定义与使用方法.分享给大家供大家参考,具体如下: 和单链表类似,只不过是增加了一个指向前面一个元素的指针而已. 示意图: python 实现代码: #!/usr/bin/python # -*- coding: utf-8 -*- class Node(object): def __init__(self,val,p=0): self.data = val self.next = p self.prev = p class LinkList(obje

  • 全面了解python中的类,对象,方法,属性

    python中一切皆为对象,所谓对象:我自己就是一个对象,我玩的电脑就是对象,坐着的椅子就是对象,家里养的小狗也是一个对象...... 我们通过描述属性(特征)和行为来描述一个对象的.比如家里的小狗,它的颜色,大小,年龄,体重等是它的属性或特征.它会汪汪叫,会摇尾巴等是它的行为. 我们在描述一个真实对象(物体)时包括两个方面: 它可以做什么(行为) 它是什么样的(属性或特征). 在python中,一个对象的特征也称为属性(attribute).它所具有的行为也称为方法(method) 结论:对象

  • 深入解析C++编程中基类与基类的继承的相关知识

    基类 继承过程将创建一个新的派生类,它由基类的成员加上派生类添加的任何新成员组成.在多重继承中,可以构建一个继承关系图,其中相同的基类是多个派生类的一部分.下图显示了此类关系图. 单个基类的多个实例 在该图中,显示了 CollectibleString 和 CollectibleSortable 的组件的图形化表示形式.但是,基类 Collectible 位于通过 CollectibleSortableString 路径和 CollectibleString 路径的 CollectibleSor

随机推荐