Python笔记 · 魔法函数 / Magic Methods / Dunder Methods

news2024/11/16 17:52:42

在上篇文章《Python笔记 · 私有方法、私有属性 & 单下划线、双下划线》我们介绍过以前置双下划线开始,后置双下划线结束的方法名:__*__,这是系统定义的一批特殊函数,通常被称之为:魔法函数(Magic Methods 或 Dunder Methods),其中Dunder意为:“Double Under (Underscores)”。本文我们就对这些Dunder函数做一次系统介绍。

魔法函数并不会被直接调用,而在类的某些特殊行为发生时被自动调用。实际上,从其他语言观察Python的这些魔法函数,都有对应的解决方案,只是Python选择了这种“内置的预定义的函数”作为Python的处理方式。我个人倾向于把这些魔法函数分为:

  • 对象生命周期相关的操作
  • 对象基本操作(属性,toString等)
  • 运算符重载
  • 集合相关操作
  • with上下文管理器
  • 协程相关

在这里插入图片描述

(注:上图引用自:https://zhuanlan.zhihu.com/p/344951719)

以下是各魔法方法的列表:

方法名用途
__init__Initialise object
__new__Create object
__del__Destroy object
__repr__Compute “official” string representation / repr(obj)
__str__Pretty print object / str(obj) / print(obj)
__bytes__bytes(obj)
__format__Custom string formatting
__lt__obj < …
__le__obj <= …
__eq__obj == …
__ne__obj != …
__gt__obj > …
__ge__obj >= …
__hash__hash(obj) / object as dictionary key
__bool__bool(obj) / define Truthy/Falsy value of object
__getattr__Fallback for attribute access
__getattribute__Implement attribute access: obj.name
__setattr__Set attribute values: obj.name = value
__delattr__Delete attribute: del obj.name
__dir__dir(obj)
__get__Attribute access in descriptor
__set__Set attribute in descriptor
__delete__Attribute deletion in descriptor
__init_subclass__Initialise subclass
__set_name__Owner class assignment callback
__instancecheck__isinstance(obj, …)
__subclasscheck__issubclass(obj, …)
__class_getitem__Emulate generic types
__call__Emulate callables / obj(*args, **kwargs)
__len__len(obj)
__length_hint__Estimate length for optimisation purposes
__getitem__Access obj[key]
__setitem__obj[key] = … or `obj[]
__delitem__del obj[key]
__missing__Handle missing keys in dict subclasses
__iter__iter(obj) / for … in obj (iterating over)
__reversed__reverse(obj)
__contains__… in obj (membership test)
__add__obj + …
__radd__… + obj
__iadd__obj += …
__sub__obj - …
__mul__obj * …
__matmul__obj @ …
__truediv__obj / …
__floordiv__obj // …
__mod__obj % …
__divmod__divmod(obj, …)
__pow__obj ** …
__lshift__obj << …
__rshift__obj >> …
__and__obj & …
__xor__obj ^ …
__or__obj
__neg__-obj (unary)
__pos__+obj (unary)
__abs__abs(obj)
__invert__~obj (unary)
__complex__complex(obj)
__int__int(obj)
__float__float(obj)
__index__Losslessly convert to integer
__round__round(obj)
__trunc__math.trunc(obj)
__floor__math.floor(obj)
__ceil__math.ceil(obj)
__enter__with obj (enter context manager)
__exit__with obj (exit context manager)
__await__Implement awaitable objects
__aiter__aiter(obj)
__anext__anext(obj)
__aenter__async with obj (enter async context manager)
__aexit__async with obj (exit async context manager)

(注:更多关联到官方文档的解释,请参考:https://mathspp.com/blog/pydonts/dunder-methods#fn:2)

由于方法众多,我们可以使用下述方法来查看当前对象所有的函数,所有的魔法函数也会罗列出来。

dir(<your-object>)

由于魔法函数众多,我们不会在本文中一一解读,以后在使到的场景中再跟进做一些笔记。本文,我们只关注一部分最基本也最常见的魔法函数。

__init__()

总是第一个被提起的魔法函数,实际上就是Python的构造函数。该函数会在对象初始化的时由解释器自动调用,程序员可以自由选择实现或不实现,但就像其他编程语言中的构造函数一样,一般都会选择实现。如果不实现,则对象属性是不会被声明和初始化的,虽然Python是动态语言,在后续使用对象的过程中依然可以随时添加和初始化属性,但是从编程习惯上讲,还是在构造函数中显示声明出所有属性是更好的选择。

__new__()

在object类中存在一个静态的__new__(cls, *args, **kwargs) 方法,该方法需要传递一个参数 cls,cls 表示需要实例化的类,此参数在实例化时由 Python 解释器自动提供,__new__ 方法必须有返回值,且返回的是被实例化的实例,只有在该实例返回后才会调用__init__ 来进行初始化,初始化所用的实例就是__new__ 返回的结果,也就可以认为是 self。

__init____new__的区别

  • __new__的调用发生在__init__之前
  • __new__是类级别的方法(方法参数是cls),__init__是实例级别的方法(方法参数是self)

当我们创建一个Python实例时,Python会先调用__new__来创建一个实例,然后再调用这个实例的__init__方法来完成一些实例属性的初始化操作。

绝大多数情况下, 我们只需要实现__init__方法,关于__new__有两种典型的应用场景:

当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。

  1. 当我们要继承一些不可变类时,__new__给了我们一个“调整”这些类的实例化细节的入口,例如如下代码:
class PositiveInteger(int):
    def __new__(cls, value):
        return super(PositiveInteger, cls).__new__(cls, abs(value))
i = PositiveInteger(-3)
print(i)

由于Int是不可变类,继承自它的PositiveInteger会自动取绝对值作为其值。尽管该意图在init方法中同样可以实现,但是在类级别的new方法中实现是更合理的,应为是类型(即PositiveInteger)本身的固有特性。

  1. 通过__new__实现单例
class Single(object):
    _instance = None
    def __new__(cls, *args, **kw):
        if cls._instance is None:
            cls._instance = object.__new__(cls, *args, **kw)
        return cls._instance
    def __init__(self):
        pass

single1 = Single()
single2 = Single()

single1.attr1='value1'
print(single1.attr1)
print(single2.attr1)
print(id(single1) == id(single2))

程序输出:

value1
value1
True

基于new实现的单例能很好地体现new区别于init的地方。

__iter__()

只要定义了__iter__() 方法对象,就是可迭代对象;这意味着,我们可以迭代我们自己定义的对象。

__next__()

函数next() 是 iterator 区别于 iterable 的关键,它允许我们显式地获取一个元素。当调用 next() 方法时,实际上产生了 2 个操作:一是更新 iterator 状态,令其指向后一项,以便下一次调用,二是返回当前结果。

__call__()

对象通过提供__call__() 方法可以模拟函数的行为,如果一个对象提供了该方法,就可以像函数一样使用它。

__len__()

len 调用后会调用对象的__len__ 函数,我们可以为其定制输出。

__str__()

直接打印对象的实现方法,str 是被 print 函数调用的,一般都是 return 一个什么东西,这个东西应该是以字符串的形式表现的。如果不是要用 str() 函数转换,我们可以直接 print 的对象都是实现了__str__ 这个方法的,比如 dict。

__repr__()

函数 str() 用于将值转化为适于人阅读的形式,而 repr() 转化为供解释器读取的形式,某对象如果没有适于人阅读的解释形式的话,我们可以定制__repr__ 的输出。

__setitem__()

该函数可以给对象赋值,我们可以以下标的方式对其进行操作

__getitem__()

与上函数相反,getitem 可以使对象支持以下标的方式获取值。

__delitem__()

该函数支持以下标方式删除对象数据,实现了这三个函数,这个类就像字典一样,具备了基本的增删查功能,有时候这样写会很方便。

__del__()

这可以说是一个析构器,或者回收器,在对象引用数降到0时执行,有时可能还需要等一会再执行,所以一般不推荐使用,但是在代码中我们偶尔可以用它来实现一些必须要做的,但是并不紧急的事。

__setattr__()

该函数可以设置函数的属性。

__getattr__()

获取对象属性,只有在属性没有找到的时候调用。

__getattribute__()

该函数和上面介绍的__getattr__ 很像,都是获取属性,但是__getattr__ 是在属性不存在时被调用,而__getattribute__ 是无条件被调用,这样会方便我们做一些控制,需要注意,一旦定义 了__getattribute__,则__getattr__ 不再会被调用,除非显式调用。

##__delattr__()
本函数的作用是删除属性,实现了该函数的类可以用 del 命令来删除属性。


参考:

https://www.cnblogs.com/chenhuabin/p/13752770.html

https://levelup.gitconnected.com/python-dunder-methods-ea98ceabad15

https://www.tutorialsteacher.com/python/magic-methods-in-python

https://mathspp.com/blog/pydonts/dunder-methods

https://lupanlpb.github.io/2019/08/14/Python%E5%B8%B8%E7%94%A8%E9%AD%94%E6%B3%95%E5%87%BD%E6%95%B0/

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5-2:Kafka入门

Kafka简介 原本的kafka只是一个处理消息队列的技术&#xff0c;但随着功能不断增加&#xff0c;不断综合&#xff0c;成为了一个分布式的流媒体平台 Kafka是一个分布式的流媒体平台。 应用&#xff1a;消息系统、日志收集、用户行为追踪、流式处理。 Kafka特点 高吞吐量、消息…

电源模块测试解决方案-电源测试系统方案-电源模块测试报告NSAT-8000

*测试仪器&#xff1a;可编程直流电源、可编程直流电子负载、数字示波器、功率计 *测试产品&#xff1a;电源模块。纳米软件电源ATE自动测试系统适用于大功率工业电源、AC/DC类DC电源供应器、适配器、充电器、LED电源等开关电源之综合性能测试。 *被测项目&#xff1a;有效值电…

目标检测之多尺度融合

多尺度 卷积神经网络通过逐层抽象的方式来提取目标的特征&#xff0c;其中一个重要的概念就是感受野。 高层网络的感受野比较大&#xff0c;语义信息表征能力强&#xff0c;但是特征图的分辨率低&#xff0c;几何信息的表征能力弱&#xff08;空间几何特征细节缺乏&#xff09…

深入React源码揭开渲染更新流程的面纱

转前端一年半了&#xff0c;平时接触最多的框架就是React。在熟悉了其用法之后&#xff0c;避免不了想深入了解其实现原理&#xff0c;网上相关源码分析的文章挺多的&#xff0c;但是总感觉不如自己阅读理解来得深刻。于是话了几个周末去了解了一下常用的流程。也是通过这篇文章…

深入了解Spring循环依赖本质

说明: 1. 本文基于Spring-Framework 5.1.x版本讲解 2. 建议读者对创建对象部分源码有一定了解 概述 这篇讲讲Spring循环依赖的问题&#xff0c;网上讲循环依赖的帖子太多太多了&#xff0c;相信很多人也多多少少了解一点&#xff0c;那我还是把这个问题自己梳理一遍&#xff…

kubernetes,service详解下

kubernetes&#xff0c;service详解下 HeadLiness类型的Service 在某些场景中&#xff0c;开发人员可能不想使用Service提供的负载均衡功能&#xff0c;而希望自己来控制负载均衡策略&#xff0c;针对这种情况&#xff0c;kubernetes提供了HeadLiness Service&#xff0c;这类…

内存分段与内存分页:逻辑地址、物理地址、线性地址、虚拟地址

这篇文章也是我自己的博客网站的里的文章&#xff0c;我觉得这篇文章还是我觉得知识含量比较高的文章&#xff0c;所以特地把它发出来看看。 这篇文章写于我在写自己的操作系统JackOS的时候系统梳理了一下CPU访问内存的各种方式&#xff0c;写完这篇文章之后&#xff0c;我对C…

Kafka高级特性解析之生产者

1、消息发送 1.1、数据生产流程解析 Producer创建时&#xff0c;会创建一个Sender线程并设置为守护线程。生产消息时&#xff0c;内部其实是异步流程&#xff1b;生产的消息先经过拦截器->序列化器->分区器&#xff0c;然后将消息缓存在缓冲区&#xff08;该缓冲区也是在…

Docker桌面版安装与使用(windows)

目录一、Docker概念二、下载安装三、docker镜像安装与操作四、制作自己的python镜像容器五、目录挂载六、多容器通信七、Docker-Compose管理多个容器运行八、发布和部署九、备份数据迁移一、Docker概念 1、Docker 是一个应用打包、分发、部署的工具2、镜像Image、容器Containe…

Windows OpenGL 图像绿幕抠图

目录 一.OpenGL 图像绿幕抠图 1.原始图片2.效果演示 二.OpenGL 图像绿幕抠图源码下载三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 特效 零基础 Open…

[问题解决方案](多人共同合并场景)git已merge到master分支代码且被同事代码覆盖如何回退

git已merge到master分支代码如何回退&#xff08;多人共同合并&#xff09;场景已经被同事代码覆盖的解决方案&#xff08;无需强制合并权限&#xff09;代码revert后又需要重新启用怎么办如果是未受保护分支代码的回退且只有你一人合并的代码 可以直接使用下面的命令即可如果只…

【Unity3D日常开发】Unity3D中实现不规则Button按钮的精准响应

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客QQ群&#xff1a;1040082875 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 在使用Unity3D开发中&#xff0c;可…

全志V853平台Camera模块开发框架详解

Camera 本章节介绍V853平台 Camera 模块的开发。 V853支持并口CSI、MIPI&#xff0c;使用VIN camera驱动框架。 Camera通路框架 VIN支持灵活配置单/双路输入双ISP多通路输出的规格 引入media框架实现pipeline管理 将libisp移植到用户空间解决GPL问题 将统计buffer独立为v…

Web大学生网页作业成品——抗击疫情网站设计与实现(HTML+CSS)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Vue3 样式绑定

Vue3 样式绑定1.Vue.js class2.class 属性绑定3.Vue.js style(内联样式)4.组件上使用 class 属性1.Vue.js class class 与 style 是 HTML 元素的属性&#xff0c;用于设置元素的样式&#xff0c;我们可以用 v-bind 来设置样式属性。 v-bind 在处理 class 和 style 时&#xf…

微信小程序反编译

本文转载于&#xff1a;https://www.cnblogs.com/one-seven/p/15524457.html 微信小程序反编译 微信文件保存位置\WeChat Files\Applet\小程序id_APP_.wxapkg 现在小程序是处于编码状态 github上下载一个python版的解密工具 https://github.com/superdashu/pc_wxapkg_decr…

【免杀前置课——Windows编程】十四、异步IO——什么是异步IO、API定位问题、APC调用队列

异步IO异步IO异步I/0注意事项:定位问题总解决方案APC调用队列异步IO 当我们读取一个文件时&#xff0c;一般情况下&#xff0c;线程是阻塞的&#xff0c;也就是说&#xff0c;当前线程在等待文件读取操作结束,这种方式叫同步IO。 Windows 在系统底层为用户实现了另外一种高效的…

【软考】-- 操作系统(下)

操作系统&#xff08;下&#xff09;第五节 文件管理&#x1f355;一、文件管理的基本概念1️⃣文件2️⃣文件目录3️⃣目录结构:&#x1f354;二、文件路径&#x1f35f;三、文件命名规则&#x1f32d;四、文件的基本操作&#x1f37f;五、文件类型与扩展名&#x1f9c2;六、系…

Docker中安装Kibana

Kibana是一个免费且开放的用户界面,能够让你对Elasticsearch 数据进行可视化,并让你在Elastic Stack中进行导航。你可以进行各种操作,从跟踪查询负载,到理解请求如何流经你的整个应用,都能轻松完成。 在Docker Hub中选择最新版本的Kibaba镜像(选择版本为8.5.1),如下图…

bigquant选股模型主要有哪些?

bigquant选股模型一般常见的有七种&#xff0c;即多因子模型、风格轮动模型、行业轮动模型、资金流模型、动量反转模型、一致预期模型、趋势追踪模型等方面。不过要想样样都学会精通也是需要花费时间&#xff0c;以及精力等&#xff0c;那么&#xff0c;小编就从最基本的多因子…