python 抽象接口和协议总结

通过实现特殊方法,自定义数据类型可以表现得跟内置类型一样,从而让我们写出更具表达力的代码——或者说,更具 Python 风格的代码。

功能协议接口
+__add__
*__mul__
str()先查找是否实现 __str__ 协议,没有查找是否实现 __repr__
bool()默认情况下,我们自己定义的类的实例总被认为是真的,除非这个类对 __bool__ 或者 __len__ 函数有自己的实现。bool(x) 的背后是调用 x.__bool__() 的结果;如果不存在 __bool__ 方法,那么 bool(x) 会尝试调用 x.__len__()。若返回 0,则 bool 会返回 False;否则返回 True
字符串 / 字节序列 表示形式__repr__、__str__、__format__、__bytes__
数值转换__abs__、__bool__、__complex__、__int__、__float__、__hash__、__index__
集合模拟__len__、__getitem__、__setitem__、__delitem__、__contains__
迭代枚举__iter__、__reversed__、__next__
可调用模拟__call__
上下文管理__enter__、__exit__
实例创建和销毁__new__、__init__、__del__
属性管理__getattr__、__getattribute__、__setattr__、__delattr__、__dir__
属性描述符__get__、__set__、__delete__
跟类相关的服务__prepare__、__instancecheck__、__subclasscheck__
一元运算符__neg__ -、__pos__ +、__abs__ abs()
众多比较运算符__lt__ <、__le__ <=、__eq__ ==、__ne__ !=、__gt__ >、__ge__ >=
算术运算符__add__ +、__sub__ -、__mul__ *、__truediv__ /、__floordiv__ //、__mod__ %、__divmod__ divmod()、__pow__ ** 或 pow()、__round__ round()
反向算术运算符__radd__、__rsub__、__rmul__、__rtruediv__、__rfloordiv__、__rmod__、__rdivmod__、__rpow__
增量赋值算术运算符__iadd__、__isub__、__imul__、__itruediv__、__ifloordiv__、__imod__、__ipow__
位运算符__invert__ ~、__lshift__ <<、__rshift__ >>、__and__ &、__or__ |、__xor__ ^
反向位运算符__rlshift__、__rrshift__、__rand__、__rxor__、__ror__
增量赋值位运算符__ilshift__、__irshift__、__iand__、__ixor__、__ior__

更具体细致的表格总结如下

1.基础知识
在这里插入图片描述
在这里插入图片描述

  • __init__() 方法的调用发生在实例被创建 之后 。如果要控制实际创建进程,请使用 __new__() 方法
  • 按照约定, __repr__() 方法所返回的字符串为合法的 Python表达式。
  • 在调用 print(x) 的同时也调用了 __str__() 方法。
  • 由于 bytes 类型的引入而从 Python 3 开始出现
  • 按照约定,format_spec 应当遵循 迷你语言格式规范Python 标准类库中的decimal.py 提供了自己的 __format__() 方法。

2.行为方式与迭代器类似的类

在这里插入图片描述

  • 无论何时创建迭代器都将调用 __iter__() 方法。这是用初始值对迭代器进行初始化的绝佳之处。
  • 无论何时从迭代器中获取下一个值都将调用 __next__() 方法。
  • __reversed__() 方法并不常用。它以一个现有序列为参数,并将该序列中所有元素从尾到头以逆序排列生成一个新的迭代器

3.计算属性
在这里插入图片描述
在这里插入图片描述

  • 如果某个类定义了 __getattribute__() 方法,在 每次引用属性或方法名称时 Python 都调用它(特殊方法名称除外,因为那样将会导致讨厌的无限循环)
  • 如果某个类定义了 __getattr__() 方法,Python 将只在正常的位置查询属性时才会调用它。如果实例 x 定义了属性 colorx.color 将 不会 调用 x.__getattr__('color');而只会返回x.color 已定义好的值。
  • 无论何时给属性赋值,都会调用 __setattr__() 方法。
  • 无论何时删除一个属性,都将调用 __delattr__() 方法。
  • 如果定义了 __getattr__()__getattribute__() 方法,__dir__() 方法将非常有用。通常,调用 dir(x) 将只显示正常的属性和方法。如果 __getattr()__ 方法动态处理 color 属性,dir(x) 将不会将 color 列为可用属性。可通过覆盖 __dir__()方法允许将 color 列为可用属性,对于想使用你的类但却不想深入其内部的人来说,该方法非常有益。

__getattr__()__getattribute__() 方法的区别非常细微,但非常重要。可以用两个例子来解释一下

# -*- coding: utf-8 -*-


class Dynamo:

    # 属性名称以字符串的形式传入 __getattr()__ 方法。如果名
    # 称为 'color',该方法返回一个值。(在此情况下,它只是一个
    # 硬编码的字符串,但可以正常地进行某些计算并返回结果。)
    def __getattr__(self, key):
        if key == 'color':
            return 'PapayaWhip'
        else:
            # 如果属性名称未知, __getattr()__ 方法必须引发一个
            # AttributeError 例外,否则在访问未定义属性时,代码将只会
            # 默默地失败。(从技术角度而言,如果方法不引发例外或显式
            # 地返回一个值,它将返回 None ——Python 的空值。这意味着 所
            # 有 未显式定义的属性将为 None,几乎可以肯定这不是你想看到
            # 的。)
            raise AttributeError


if __name__ == '__main__':
    dyn = Dynamo()
    # dyn 实例没有名为 color 的属性,因此在提供计算值时将调用
    # __getattr__() 。  
    print(dyn.color)
    # PapayaWhip
    
    dyn.color = 'LemonChiffon'
    # 在显式地设置 dyn.color 之后,将不再为提供 dyn.color 的
    # 值而调用 __getattr__() 方法,因为 dyn.color 已在该实例中定
    # 义。
    print(dyn.color)
    # LemonChiffon


另一方面,__getattribute__() 方法是绝对的、无条件的。

# -*- coding: utf-8 -*-


class SuperDynamo:

    def __getattribute__(self, key):
        if key == 'color':
            return 'PapayaWhip'
        else:
            raise AttributeError


if __name__ == '__main__':
    dyn = SuperDynamo()

    # 在获取 dyn.color 的值时将调用 __getattribute__() 方法
    print(dyn.color)
    # PapayaWhip
    dyn.color = 'LemonChiffon'
    # 即便已经显式地设置 dyn.color,在获取 dyn.color 的值时,
    # 仍将调用 __getattribute__() 方法。如果存在
    # __getattribute__() 方法,将在每次查找属性和方法时 无条件
    # 地调用 它,哪怕在创建实例之后已经显式地设置了属性。
    print(dyn.color)
    # PapayaWhip

tips:
如果定义了类的 __getattribute__()方法,你可能还想定义一个 __setattr__()方法,并在两者之间进行协同,以跟踪属
性的值。否则,在创建实例之后所设置的值将会消失在黑洞中。

必须特别小心 __getattribute__() 方法,因为 Python查找类的方法名称时也将对其进行调用。

# -*- coding: utf-8 -*-


class Rastan:

    def __getattribute__(self, key):
        # 该类定义了一个总是引发 AttributeError 例外的
        # __getattribute__() 方法。没有属性或方法的查询会成功。  
        raise AttributeError

    def swim(self):
        return "swim"


if __name__ == '__main__':
    hero = Rastan()
    # 调用 hero.swim() 时,Python 将在 Rastan 类中查找 swim()
    # 方法。该查找将执行整个 __getattribute__() 方法,因为所有
    # 的属性和方法查找都通过 __getattribute__() 方法。在此例
    # 中, __getattribute__() 方法引发 AttributeError 例外,因此
    # 该方法查找过程将会失败,而方法调用也将失败。
    hero.swim()
    # Traceback (most recent call last):
    #   File "C:/myFiles/company_project/xbot/my_test/getattribute_test.py", line 22, in <module>
    #     hero.swim()
    #   File "C:/myFiles/company_project/xbot/my_test/getattribute_test.py", line 9, in __getattribute__
    #     raise AttributeError
    # AttributeError


4.行为方式与函数类似的类
可以让的实例变得可调用——就像函数可以调用一样——通过定义 __call__() 方法。

在这里插入图片描述
5.行为方式与序列类似的类
如果作为一系列值的容器出现——也就是说如果对某个类来说,是否“包含”某值是件有意义的事情——那么它也许应该定义
下面的特殊方法已,让它的行为方式与序列类似。

在这里插入图片描述
6.行为方式与字典类似的类
在这里插入图片描述

7.行为方式与数值类似的类

使用适当的特殊方法,可以将类的行为方式定义为与数字相仿。也就是说,可以进行相加、相减,并进行其它数学运算
在这里插入图片描述
在这里插入图片描述

之前提到的特殊方法集合采用了第一种方式:对于给定 x / y,它们为 x 提供了一种途径来表述“我知道如何将自己除以 y。”下
面的特殊方法集合采用了第二种方法:它们向 y 提供了一种途径来表述“我知道如何成为分母,并用自己去除 x
在这里插入图片描述
在这里插入图片描述
对于复合运算(原地操作符)
在这里插入图片描述
在这里插入图片描述
注意:多数情况下,并不需要原地操作方法。如果未对特定运算定义“就地”方法,Python 将会试着使用(普通)方法。例
如,为执行表达式 x /= yPython 将会:

  • 试着调用 x.__itruediv__(y)。如果该方法已经定义,并返回了 NotImplemented 之外的值,那已经大功告成了。
  • 试图调用 x.__truediv__(y)。如果该方法已定义并返回一个NotImplemented 之外的值, x 的旧值将被丢弃,并将所返回的
    值替代它,就像是进行了 x = x / y 运算。
    试图调用 y.__rtruediv__(x)。如果该方法已定义并返回了一个 NotImplemented 之外的值,x 的旧值将被丢弃,并用所返回值进行替换

因此如果想对原地运算进行优化,仅需像 __itruediv__() 方法一样定义“原地”方法。否则,基本上 Python 将会重新生成原地
运算公式,以使用常规的运算及变量赋值。

还有一些“一元”数学运算,可以对“类‐数字”对象自己执行
在这里插入图片描述
在这里插入图片描述

8.可比较的类

如果要创建自己的类,且对象之间的比较有意义,可以使用下面的特殊方法来实现比较。
在这里插入图片描述
tips:
如果定义了 __lt__() 方法但没有定义__gt__()方法,Python 将通过经交换的算子调用 __lt__() 方法。然而,Python 并不
会组合方法。例如,如果定义了 __lt__()方法和 __eq()__ 方法,并试图测试是否 x<= yPython 不会按顺序调用 __lt__()__eq()__ 。它将只调用 __le__() 方法。

9.可序列化的类

Python 支持 任意对象序列化反序列化。(多数 Python 参考资料称该过程为 “pickling” 和 “unpickling”)。该技术对与将状态保存为文件并在稍后恢复它非常有意义。所有的 内置数据类型 均已支持 pickling 。如果创建了自定义类,且希望它能够pickle,阅读 pickle 协议 了解下列特殊方法何时以及如何被调用。
在这里插入图片描述
在这里插入图片描述
重建序列化对象,Python 需要创建一个和被序列化的对象看起来一样的新对象,然后设置新对象的所有属性。__getnewargs__() 方法控制新对象的创建过程,而__setstate__() 方法控制属性值的还原方式

10.可在WITH语块中使用的类
with 语块定义了 运行时刻上下文环境;在执行 with 语句时将“进入”该上下文环境,而执行该语块中的最后一条语句将“退出
该上下文环境。
在这里插入图片描述
__exit__() 方法将总是被调用,哪怕是在 with 语块中引发了例外。实际上,如果引发了例外,该例外信息将会被传递给 __exit__() 方法。查阅 With 状态上下文环境管理器 了解更多细节。

11.真正神奇的东西

如果知道自己在干什么,你几乎可以完全控制类是如何比较的、属性如何定义,以及类的子类是何种类型。
在这里插入图片描述
在这里插入图片描述
tips: 确切掌握 Python 何时调用 __del__() 特别方法 是件难以置信的复杂事情。要想完全理解它,必须清楚 Python 如何在内存中跟踪对象。了解 Python 垃圾收集和类析构器。还可以阅读 《弱引用》、《weakref 模块》,还可以将 《gc模块》 当作补充阅读材料。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/334329.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器人导纳控制实现框架

Safe, Stable and Intuitive Control for Physical Human-Robot Interaction - 知乎关于文章《Safe, Stable and Intuitive Control for Physical Human-Robot Interactio》的简记。 Safe, Stable and Intuitive Control for Physical Human-Robot Interaction目的根据力导数作…

计算机找不到msvcp120.dll的修复方法,总结五种可靠的方法

在计算机使用过程中&#xff0c;遭遇“找不到msvcp120.dll”这一问题的困扰是许多用户都可能遇到的情况。这一特定的系统文件msvcp120.dll&#xff0c;作为Microsoft Visual C Redistributable Package的重要组成部分&#xff0c;对于运行某些应用程序至关重要。当系统提示无法…

【办公类-21-03】20240119 提取不连续的男女学号 set()和list法

背景需求&#xff1a;了解班级幼儿性别比例 查看点名册&#xff0c;发现中4班最初的学号是按照先男后女的方式排列&#xff0c;但是随着幼儿转出&#xff0c;空出一些学号&#xff0c;于是新插班的孩子就插入空的学号&#xff0c;空格插完了&#xff0c;就排在学号尾部。 我想…

postman导入https证书

进入setting配置中Certificates配置项 点击“Add Certificate”,然后配置相关信息 以上配置完毕&#xff0c;如果测试出现“SSL Error:Self signed certificate” 则将“SSL certificate verification”取消勾选

Jmeter后置处理器——JSON提取器

目录 1、简介 2、使用步骤 1&#xff09;添加线程组 2&#xff09;添加http请求 3&#xff09; 添加JSON提取器 1、简介 JSON是一种简单的数据交换格式&#xff0c;允许互联网应用程序快速传输数据。JSON提取器可以从JSON格式响应数据中提取数据、简化从JSON原始数据中提取特定…

【AI】ChatGPT和文心一言那个更好用

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读文章&#xff01; 此篇是【话题达人】序列文章&#xff0c;这一次的话题是《自然语言处理的发展》 文章将以博主的角度进行讲述&#xff0c;理解和水平有限&#xff0c;不足之处&#xff0c;望指正。 目录 背景自我介绍面试题…

【算法理论】期末复习-选填

算法的五个特征 1.有效性 算法必须在有限的时间能够完成&#xff0c;甚至用纸和笔完成 2.确定性 算法的每一步能够清楚的定义. 3.有限性 算法能够在有限的步骤完成 4.Input 算法有0个或者多个输入 5.Output 算法有一个或者多个输出 满足有效性&#xff0c;确定性&am…

adb 配对+无线连接

配对 打开手机开发者选项-无线调试-使用配对码配对设备 出现ip端口和配对码后&#xff0c;电脑输入命令&#xff1a; adb pair ip:端口 eg:adb pair 192.168.137.244:39683 提示输入配对码&#xff1a;就按照手机上的输入。 此时配对成功 连接 再使用命令adb connect ip:port…

IDEA项目启动报错之Command too long

使用IDEA最新的版本2023-3月份社区版本&#xff0c;启动之前没问题的项目突然报错如下&#xff1a; Error running VipServiceApplication: Error running // VipServiceApplication.Command line is too long. Shorten the command line via // JAR manifest or via a // clas…

IPFoxy运营干货|谷歌广告Google Ads如何选择最佳关键词?

投放谷歌广告需要多少个步骤和什么准备工作&#xff0c;本文将来讲述&#xff0c;主要分5个内容&#xff1a;一、投放前竞对研究&#xff1b;二、投放前广告账户设置&#xff1b;三、建立广告系列&#xff1b;四、建立广告组&#xff1b;五、广告长期策略。 一、投放前竟对研究…

RabbitMQ的基本使用,进行实例案例的消息队列

目录 一、介绍 1. 概述 2. 作用 3. 工作原理 二、RabbitMQ安装部署 1. 安装 2. 部署 3. 增加用户 三、实现案例 1. 项目创建 2. 项目配置 3. 生产者代码 4. 消费者代码 四、测试 每篇一获 一、介绍 1. 概述 RabbitMQ 是一种开源的消息代理和队列服务器&#x…

【RocketMQ每日一问】RocketMQ nameserver的作用是什么?

Name Server 在 Apache RocketMQ 集群中扮演着以下几个重要作用&#xff1a; 服务注册与发现&#xff1a; Name Server 负责管理和协调整个集群&#xff0c;维护集群中所有 Broker 的信息&#xff0c;包括 Broker 的 IP 地址、端口号、存储容量等。当 Producer 和 Consumer 需…

内存分析CE寻找天龙八部人物状态及基址

扫描类型为未知的数值首次扫描 通过改变角色状态 扫描类型变动的数值和未变动的数值扫描地址 选择3FCBD25C为人物状态地址 0站立 2走路 6打坐 7打怪 找基址 鼠标右键找出是什么访问了这个地址 查看第一个的详细信息 与02 和 00 进行判断&#xff08;走路和站立&#…

Architecture Lab:part A 【实现sum_list/rsum_list/copy_block/熟悉Y86-64指令】

Architecture Lab 对应CS:APP的Chap 4——处理器体系结构。Part A要实现三个函数&#xff0c;分别为sum_list/rsum_list/copy_block。建议先得到x86-64指令&#xff0c;然后再转换为Y86-64指令。 准备工作 在misc目录下&#xff0c;键入以下命令用来生成汇编代码。命令执行完…

Linux快速部署文件服务器

参考文档&#xff1a; Linux命令之nohup详解 - 掘金 【Linux】ps -ef|grep详解-CSDN博客 有个简单想法&#xff0c;我的一些文件放在机器某个目录下面&#xff0c;可以简单提供团队内部人员浏览和下载功能&#xff0c;节约时间&#xff0c;用最简单方法实现。 注&#xff1a;…

MyBatisPlus学习笔记五-插件功能

0、插件功能 MyBatisPlus提供的内置拦截器有下面这些 1、分页插件 2、通用分页实体 3、通用分页实体-强化 需求&#xff1a; 在PageQuery中定义方法&#xff0c;将PageQuery对象转为MyBatisPlus中的Page对象在PageDTO中定义方法&#xff0c;将MyBatisPlus中的Page结果转为Page…

mysql原理--事务的隔离级别与 MVCC

1.事前准备 为了故事的顺利发展&#xff0c;我们需要创建一个表&#xff1a; CREATE TABLE hero (number INT,name VARCHAR(100),country varchar(100),PRIMARY KEY (number) ) EngineInnoDB CHARSETutf8;然后向这个表里插入一条数据&#xff1a;INSERT INTO hero VALUES(1, 刘…

想做一名严肃的伦敦金投资者?那请做好以下这两个准备

在伦敦金市场中&#xff0c;如果投资者想成为一名脚踏实地的投资者&#xff0c;首先要在心态上、思想上对自己进行改造&#xff0c;起码接受自己是严肃投资者的身份&#xff0c;然后再完成下面我们提出的这两种准备。 选择一种自己喜欢的交易策略。既然要成为一名严肃的投资者&…

栈、队列专题

文章目录 栈栈的概述栈的实现栈在函数调用中的应用栈在表达式求值中的应用逆波兰表达式求值 栈在括号匹配中的应用有效的括号最长的有效括号删除字符串中的所有相邻重复项 如何获取栈内最小元素呢如何实现浏览器的前进和后退 队列队列的定义队列的实现循环队列队列的应用队列在…

Pytorch实战——3、数据加载与处理

&#x1f345; 写在前面 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;这里是hyk写算法了吗&#xff0c;一枚致力于学习算法和人工智能领域的小菜鸟。 &#x1f50e;个人主页&#xff1a;主页链接&#xff08;欢迎各位大佬光临指导&#xff09; ⭐️近…
最新文章