Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python中的接口协议和抽象基类

Python中的接口协议和抽象基类

作者头像
dongfanger
发布于 2021-09-28 02:00:57
发布于 2021-09-28 02:00:57
2K00
代码可运行
举报
文章被收录于专栏:dongfangerdongfanger
运行总次数:0
代码可运行

Python接口与协议

Python语言是没有interface关键字的,这也是动态类型语言的特点之一。Python的接口指的是类实现或继承的公开属性,包括数据或方法。比如Sequence的正式接口如下图所示:

这些都叫做Python接口。事实上,Python每个类都有接口,除了抽象基类

接口是正式的,它定义了类具有哪些属性,协议是非正式的接口,只由文档和约定定义。比如只要类实现了__getitem__方法,按照序列协议的约定,Python就会支持这个类完成访问元素、迭代和使用in运算符等一系列操作。

猴子补丁

我们可以通过猴子补丁来进一步认识,Python中协议的约定是怎么回事。猴子补丁是这样一种技术:在运行时修改类或模块,而不改动源码。还是以序列协议来举例,比如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> from random import shuffle
>>> from frenchdeck import FrenchDeck
>>> deck = FrenchDeck()
>>> shuffle(deck)

假设运行报错了:TypeError: 'FrenchDeck' object does not support item assignment,因为FrenchDeck类只有__getitem__方法,只实现了不可变的序列协议。为了解决这个报错,需要通过__setitem__方法实现可变的序列协议

代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def set_card(deck, position, card):
    deck._cards[position] = card

FrenchDeck.__setitem__ = set_card
shuffle(deck)

这就是一段猴子补丁技术的实现代码,没有修改FrenchDeck类的源码,而是在运行时动态修改。

抽象基类

Python的抽象基类是指必须让继承它的子类去实现它所要求的方法的类。Python的collections.abc模块中就定义了很多抽象基类:

虽然我们在实际编程中并不会自己编写抽象基类(一般也不建议这样做,因为可能会导致意想不到的问题),但是了解抽象基类,可以帮助我们更好理解Python面向对象的继承等概念。

抛开枯燥的理论知识,我在书中找到了一处具有实践价值的片段:

「在一连串if/elif/elif中使用isinstance做检查,然后根据对象的类型执行不同的操作,通常是不好的做法;此时应该使用多态,即采用一定的方式定义类,让解释器把调用分派给正确的方法,而不使用if/elif/elif块硬编码分派逻辑。」

交流群和公司都有人问过我这个问题,写了太多的ifelse有没有更好的实现方式,我想这里已经给出了答案。

鸭子类型和白鹅类型

Python鸭子类型是指对象的类型无关紧要,只要实现了特定的协议即可。它的好处是避免过多的isinstance,如果遵守既定协议,能增加利用现有的标准库和第三方代码的可能性。示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Animal(object):
    
    def run(self):
        print("The animal is running...")

class Dog(Animal):

    def run(self):
        print('The dog is running...')

class Cat(Animal):

    def run(self):
        print('The cat is running...')

def make_run(animal):
    animal.run()

dog = Dog()
cat = Cat()
make_run(dog)
make_run(cat)

对于 make_run() 函数来说,传入的参数并不一定需要是 Animal 类型的,只需要保证传入的对象有一个 run() 方法即可。

白鹅类型是指只要cls是抽象基类(即cls的元类是abc.ABCMeta),就可以使用isinstance(obj, cls)。它的基本特性是,即便不继承,也有办法把一个类注册为抽象基类的虚拟子类。Python不会检查虚拟子类是否实现了抽象基类要求实现的方法,而是由我们自己保证,并捕获异常。具体会在下篇文章《Python抽象基类的定义与使用》进行介绍。

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-09-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
python的抽象基类
与jvm上的语言不一样,python的语言没有interface关键字,而且除了抽象基类,每个类都有相应的接口:类实现或继承的公开属性(方法或数据类型)
哒呵呵
2018/08/06
9570
Python之抽象基类建议收藏
  以上为Animal的抽象基类,注意重写了__subclasscheck__(cls, subclass)方法来改变issubclass或者isinstance的行为,__subclasscheck__(cls, subclass)必须为@classmethod
全栈程序员站长
2022/07/14
6940
流畅的 Python 第二版(GPT 重译)(七)
面向对象编程关乎接口。在 Python 中理解类型的最佳方法是了解它提供的方法——即其接口——如 “类型由支持的操作定义”(第八章)中所讨论的。
ApacheCN_飞龙
2024/03/21
2620
流畅的 Python 第二版(GPT 重译)(七)
python 接口 、继承、重载运算符
直接子类化内置类型(如 dict、list 或 str)容易出错, 因为 内置类型的方法 通常会 忽略用户覆盖的方法。 不要子类化内置 类型,用户自己定义的类 应该继承 collections 模块 中的类,例如 UserDict、UserList 和 UserString,这些类做了特殊设计,因 此易于扩展
Michael阿明
2021/09/06
3750
Python面试题之Python面向对象编程汇总
面向对象的设计思想是从自然界中来的,因为在自然界中,类(Class)和实例(Instance)的概念是很自然的。Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念,而实例(Instance)则是一个个具体的Student,比如,Bart Simpson和Lisa Simpson是两个具体的Student。
Jetpropelledsnake21
2019/02/15
1.8K0
Python 学习笔记之类「面向对象,超类,抽象」
在面向对象编程中,术语对象大致意味着一系列数据 (属性) 以及一套访问和操作这些数据的方法。
Python技术与生活认知的分享
2018/08/01
7981
Python 学习笔记之类「面向对象,超类,抽象」
Python:多态、协议和鸭子类型
问起面向对象的三大特性,几乎每个人都能对答如流:封装、继承、多态。今天我们就要来说一说 Python 中的多态。
丹枫无迹
2019/05/14
1.1K0
Python抽象基类的定义与使用
我们写Python基本不需要自己创建抽象基类,而是通过鸭子类型来解决大部分问题。《流畅的Python》作者使用了15年Python,但只在项目中创建过一个抽象基类。我们更多时候是创建现有抽象基类的子类,或者使用现有的抽象基类注册。本文的意义在于,了解抽象基类的定义与使用,可以帮助我们理解抽象基类是如何实现的,为我们以后学习后端语言(比如Java、Golang)打下基础。毕竟抽象基类是编程语言通用设计。
dongfanger
2021/10/20
2.2K0
python高级编程第一讲:深入类和对象
多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚"鸭子类型"
小海怪的互联网
2019/08/23
6530
python高级编程第一讲:深入类和对象
python 面向对象基础 继承和多态
在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
葫芦
2019/04/17
4110
Python3.6学习笔记(三)
面向对象编程 Object Oriented Programming 简称 OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
大江小浪
2018/09/19
3990
Python3.6学习笔记(三)
22个高级Python知识点总结,干货!
众所周知,Java中强调“一切皆对象”,但是Python中的面向对象比Java更加彻底,因为Python中的类(class)也是对象,函数(function)也是对象,而且Python的代码和模块也都是对象。
玖柒的小窝
2021/12/10
1.1K0
22个高级Python知识点总结,干货!
Day9面向对象编程2/2
继承和多态 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。 比如,我们已经编写了一个名为Animal的class,有一个run()方法可以直接打印: class Animal(object): def run(self): print('Animal is running...') 当我们需要编写Dog和Cat类
林清猫耳
2018/04/26
7000
Day9面向对象编程2/2
《流畅的Python》第十一章学习笔记
协议是接口,但不是正式的,因此协议不能像正式接口那样施加限制。一个类可能只实现部分接口。
zx钟
2021/01/07
4760
送书 | 跟我一起学《流畅的Python》
本文引自图灵新书《流畅的Python》的第一章——Python数据模型。本书由奋战在Python开发一线近20年的Luciano Ramalho执笔,Victor Stinner、Alex Martelli等Python大咖担纲技术审稿人,从语言设计层面剖析编程细节,兼顾Python 3和Python 2,告诉你Python中不亲自动手实践就无法理解的语言陷阱成因和解决之道,教你写出风格地道的Python代码。 书籍信息 作者:Luciano Ramalho 译者:安道 吴珂 PSF研究员、知名Py
AI科技大本营
2018/04/26
1.2K0
送书 | 跟我一起学《流畅的Python》
python 列表的实现探析
知其然也要知其所以然,python中的容器对象真的不多,平常我们会很心安理得的根据需求来使用对应的容器,不定长数据用list,想去重用set,想快速进行匹配用dict,字符处理用str,可为何能实现这个效果呢?比如我们用list的时候,知道这玩意可以随意存储各种格式,存整型、浮点、字符串、甚至还可以嵌套list等其他容器,这底层的原理到底是用数组实现的,还是用链表?比如我们的字典,底层是用数组还是其他?如果是其他如哈希表,那又怎么实现输入数据的顺序排列?这次不妨一层层剖析,推演一番。贪多嚼不烂,本次就先对list进行分析
Yerik
2021/05/01
1.9K0
极简Python入门
本文旨在帮助从总体上帮助了解Python的一些基本属性,具体的使用技巧需要通过不断实践积累 一、Python的基本特性 二、Python的类 面向对象编程,是一种程序设计思想。OOP把对象作
智能算法
2018/04/03
1.3K0
极简Python入门
Python学习笔记(六)——面向对象编程
class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,继承的概念我们后面再讲,通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。
蛮三刀酱
2019/09/10
4140
35个高级Python知识点总结
众所周知,Java中强调“一切皆对象”,但是Python中的面向对象比Java更加彻底,因为Python中的类(class)也是对象,函数(function)也是对象,而且Python的代码和模块也都是对象。
py3study
2020/01/08
2.3K0
继承和多态
在OOP程序设计中,当定义一个class的时候,可从某个现有的class继承 新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class) 格式:
py3study
2020/01/15
4110
相关推荐
python的抽象基类
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验