【python】魔术方法大全(一)--基础篇

news2024/11/18 15:27:48

如果对你有帮助,欢迎微信搜索【海哥python】关注这个互联网苟且偷生的工具人。

什么是魔术方法

image.png
所谓魔法方法,它的官方的名字实际上叫special method,是Python的一种高级语法,允许你在类中自定义函数,并绑定到类的特殊方法中。比如在类A中自定义__str__()函数,则在调用str(A())时,会自动调用__str__()函数,并返回相应的结果。

https://docs.python.org/3/reference/datamodel.html#special-method-names

我们常常看到的Magic Methods这个名字,在官方的文档里是没有出现过的。

当然无论是magic methods还是魔术方法,这些词都被广泛的使用着。

所谓的魔术方法,是python提供的,让用户客制化一个类的方式,它顾名思义,就是定义在类里面的一些特殊的方法。
这些special method的特点,就是它的method的名字前后都有两个下划线,所以这些方法也被称为dunder methods。那包括这种前后两个下划线的形式,也叫做dunder score,它的意思就是double underscore

在我们平时写程序的时候,已经或多或少的接触过不少的魔术方法。
比如:__init__就非常非常的常用。

基础的魔术方法

__new__和__init__

首先,我们来聊一下__new____init__
这两个方法,可以让你改变从一个类建立一个对象时候的行为,这两个也比较容易被搞混。
如果你不那么了解这两个方法的机制本身,你只需要记住,__new__是从一个class建立一个object的过程。
__init__是有了这个object之后,给这个object初始化的过程。

class A:
    def __new__(cls, *args, **kwargs):
        print("__new__")
        return super().__new__(cls, *args, **kwargs)

    def __init__(self):
        print("__init__")


if __name__ == '__main__':
    a = A()

输出结果为:

__new__
__init__

我们可以看到__new____init__都被使用了。我们可以粗略的想象成:

obj = __new__(A)
__init__(obj)

如果我们在建立object的时候传入了参数,则参数既会传给__new__,也会传给__init__
在我们实际的应用中,__new__函数用到的是相对较少的。如果你不需要客制化建立这个object的过程,你只需要初始化这个object,你只需要用到__init__

那什么时候用__new__呢?

比如说,我要创建一个单例,或者一些和metaclass有关的才会用到__new__函数。

单例模式是指在整个应用程序中,某个类只能有一个实例存在,且该实例可以被任何模块访问到。这种模式的应用场景包括数据库连接池、日志对象等需要全局唯一性的对象。

简单单例

以下是一个简单的单例模式的示例代码:

class Singleton:
    _instance = None

    def __new__(cls):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance

在这个例子中,我们定义了一个名为 Singleton 的类。它包含一个类变量 _instance,该变量用于存储唯一实例的引用。

__new__ 方法中,我们检查 _instance 是否为 None。如果是,则创建一个新的实例并将其分配给 _instance。如果不是,则直接返回 _instance,而不创建新的实例。

通过这种方式,我们可以确保在应用程序中只有一个 Singleton 实例。要使用它,只需创建一个 Singleton 对象即可:

s1 = Singleton()
s2 = Singleton()

print(s1 is s2) # 输出 True

以上代码输出结果为 True,说明 s1s2 引用的是同一个实例,即单例模式实现成功。

__new__和元类(metaclass)

在 Python 中,__new__() 和元类(metaclass)之间有着紧密的联系,它们都是用来控制类的创建过程的。

元类是 Python 中的一个高级特性,它允许我们在创建类的过程中动态地修改类。元类可以通过定义 __new__() 方法来控制类的实例化过程。

在 Python 中,当我们通过 class 关键字定义一个新的类时,Python 解释器会自动调用元类来实例化类对象。

在 Python 中,使用 __call__() 方法可以实现将类的实例对象作为函数调用的效果,类似于调用一个函数。当我们调用一个类的实例对象时,Python 会自动调用这个实例对象的 __call__() 方法,从而实现了将类的实例对象作为函数调用的效果。

通过在类的 __call__() 方法中间接调用类的 __new__() 方法和 __init__() 方法,可以实现单例模式。具体而言,每次调用类的实例对象时,都会先检查已经创建的实例对象是否存在,如果存在则直接返回该实例对象,如果不存在则通过调用 __new__() 方法和 __init__() 方法来创建一个新的实例对象,并将其存储下来。由于每次都返回同一个实例对象,因此实现了单例模式。

以下是一个使用元类和 __call__() 方法实现单例模式的示例代码:

class SingletonType(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class MyClass(metaclass=SingletonType):
    pass

在上述代码中,我们首先定义了一个元类 SingletonType,这个元类重写了 __call__() 方法,用于控制类的实例化过程。在 __call__() 方法中,我们首先检查 _instances 字典中是否已经有该类的实例对象,如果已经存在,则直接返回该实例对象;如果不存在,则通过调用父类的 __call__() 方法创建一个新的实例对象,并将其存储到 _instances 字典中,然后返回该实例对象。

接下来,我们定义了一个类 SingletonClass,并将其元类设置为 SingletonType。由于 SingletonType__call__() 方法控制着 SingletonClass 的实例化过程,因此每次创建 SingletonClass 的实例对象时,都会经过 SingletonType__call__() 方法来进行处理,从而实现了单例模式。

下面是一个示例,演示了如何使用 SingletonClass 类来创建实例:

a = SingletonClass()
b = SingletonClass()

print(a is b)  # True

由于 SingletonClass 类是一个单例类,因此 ab 都是同一个实例对象,所以 a is b 的结果为 True

所以必要时,我们可以通过元类和__new__方法来控制类的创建过程。

__new__是创建object,因此它是有返回值的,必须返回这个object。
__init__没有返回值, __init__函数里面的self就是你要初始化的对象。

__del__

__del__()是delete的缩写,这是析构魔术方法。当一块空间没有了任何引用时 默认执行__del__回收这个类地址,一般我们不自定义__del__, 有可能会导致问题

  • 触发时机:当对象被内存回收的时候自动触发,有下面两种情况:

    1. 页面执行完毕回收所有变量
    2. 当多个对象指向同一地址,所有对象被del的时候
  • 功能:对象使用完毕后资源回收

  • 参数:一个self接受对象

  • 返回值:无

注意:程序自动调用__del__()方法,不需要我们手动调用。

image.png
python中对象的释放是比较复杂的。
__del__和关键字del是没有关系的,我们看到del o没有触发__del__
__del__()del关键字是两个不同的概念,虽然它们都与对象的销毁相关。

del是Python的一个关键字,用于删除变量或对象的引用。当我们执行del obj语句时,Python会将对象obj的引用计数减1,如果引用计数为0,则对象被销毁。del关键字并不会直接调用对象的__del__()方法,它只是将对象的引用计数减1,由Python自动决定是否调用__del__()方法。

__del__()方法是一个特殊方法,用于在对象被销毁时执行一些清理任务。当对象的引用计数为0时,Python会自动调用该对象的__del__()方法进行清理。__del__()方法在对象被销毁前最后一次被调用,我们可以在这个方法中执行一些需要进行清理的操作,如释放资源、关闭文件等。

需要注意的是,__del__()方法不是必须的,大多数情况下,Python会自动处理对象的销毁和内存管理,我们不需要手动定义__del__()方法。如果我们确实需要进行一些特殊的清理任务,应该尽量避免使用__del__()方法,而是使用上下文管理器、with语句等方式来管理资源和清理任务。

__repr__和__str__

__repr__(self)__str__(self)都是用于返回对象的字符串表示形式,但它们的用途不同。__repr__(self)主要用于调试和开发,而__str__(self)则主要用于用户友好的输出。
举个例子,考虑下面的Python类:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return f"Person(name={self.name}, age={self.age})"

    def __str__(self):
        return f"{self.name} is {self.age} years old"

在这个例子中,__repr__返回一个类似于构造函数调用的字符串,用于显示对象的内部状态。而__str__则返回一个可读的字符串,用于显示对象的外部状态。例如:

>>> person = Person("Alice", 25)
>>> print(person)  # 调用 __str__
Alice is 25 years old
>>> person  # 调用 __repr__
Person(name=Alice, age=25)

这样,在调试和开发时,我们可以使用__repr__方法来查看对象的内部状态,而在用户友好的输出中使用__str__方法来提供易于理解的字符串表示形式。

在实际使用中,我们可以通过内置函数repr()str()来分别获取对象的__repr____str__表示形式。例如:

p = Person("Alice", 25)
print(repr(p))  # Person('Alice', 25)
print(str(p))   # Alice (25 years old)

  • __repr__()__str__()的“备胎”,如果找不到__str__()就会找__repr__()方法。
  • %r默认调用的是__repr__()方法,%s调用__str__()方法

__formate__

__format__方法是Python中用于格式化对象输出的特殊方法。它可以让我们在使用字符串格式化方法(如str.format()f-string等)输出对象时自定义输出格式。

__format__方法有两个参数,分别为格式字符串和格式参数。格式字符串用于指定输出格式,格式参数则是要输出的参数值。其中,格式字符串是一个包含格式说明符的字符串,可以使用大括号{}来指定要输出的参数,并在大括号中使用冒号:来指定参数的格式。

下面是一个简单的例子,展示如何在类中定义__format__方法来控制输出格式:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __format__(self, format_spec):
        if format_spec == "r":
            return f"({self.y}, {self.x})"
        else:
            return f"({self.x}, {self.y})"

p = Point(1, 2)
print("Formatted point: {!r}".format(p))

在上面的例子中,我们定义了一个Point类,包含xy两个属性。我们在类中定义了__format__方法,用于控制输出格式。如果格式字符串为"r",则输出(y, x)的格式;否则输出(x, y)的格式。在最后一行,我们使用str.format()方法并传入"!r"参数来触发__format__方法,输出结果为Formatted point: (2, 1)

需要注意的是,如果我们定义了__format__方法,但在格式字符串中没有使用相应的格式说明符,那么__format__方法将不会被调用。此外,我们还可以在类中定义其他特殊方法来控制对象的输出格式,例如__str____repr__等。

微信公众号:海哥python

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

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

相关文章

Weblogic安全漫谈(四)

黑名单机制必然会推动两种研究方向的发展:一是挖掘不在黑名单的新组件,是为绕过规则;二是发掘检查的盲区,是为绕过逻辑。 CVE-2020-14756 二次反序列化具有对抗检查逻辑的天生丽质,在CVE-2018-2893中就有利用字节数组…

Kubeadmin实现k8s集群:

Kubeadmin来快速搭建一个k8s集群: 二进制搭建适合大集群,50台以上的主机, 但是kubeadm更适合中小企业的业务集群 环境: Master:20.0.0.71 2核4G 或者4核8G docker kubelet kubectl flannel Node1:20.…

面试题:vue2中option API的和vue3中composition API中的数据和方法能否交互?

结论: vue2中option API中的数据和方法可以从vue3中的composition API中进行调用, 而vue3中的composition API是不可以从vue2中的数据进行调用。 原理: 因为composition API中的函数setup在页面的生命周期中要比vue2中option API中的data、…

MR实战:词频统计

文章目录 一、实战概述二、提出任务三、完成任务(一)准备数据1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录 (二)实现步骤1、创建Maven项目2、添加相关依赖3、创建日志属性文件4、创建词频统计映射器类5、创建词频统计归并…

六、Spring 声明式事务

本章概要 声明式事务概念 编程式事务声明式事务Spring事务管理器 基于注解的声明式事务 准备工作基本事务控制事务属性:只读事务属性:超时时间事务属性:事务异常事务属性:事务隔离级别事务属性:事务传播行为 6.1 声…

phpstudy_pro 关于多版本php的问题

我在phpstudy中安装了多个PHP版本 我希望不同的网站可以对应不同的PHP版本,则在nginx配置文件中需要知道不同的PHP版本的监听端口是多少,如下图所示 然而找遍了php.ini配置,并未对listen进行设置,好奇是怎么实现不同的PHP监听不同…

AI交互提示工程指南技术

简述: 当今互联网行业对于AI提示工程的需求日益增长,而《AI提示工程指南》是一本旨在满足这种需求的宝贵指南。本指南由一位对AI提示工程充满热情并自学而来的互联网从业者撰写,旨在为行业人员提供一个全面、易懂的参考手册。 这本指南将引领您踏上AI提示工程的旅程,深入探…

【Linux】Linux Page Cache页面缓存的原理

Page cache(页面缓存)是计算机操作系统中的一种机制,用于将频繁访问的数据从磁盘存储到内存中,以便更快地访问。当程序从磁盘请求数据时,操作系统会检查该数据是否已经存在于页面缓存中。如果存在,数据可以…

猫咪主食冻干K9、希喂、SC生骨肉冻干哪款好?详细对比测评这三款产品

随着科学养猫的观念深入人心,越来越多的铲屎官开始关注猫咪主食的营养与健康。主食冻干,作为一种模拟猫咪原始猎食的食品,因其高营养保留而受到广大猫奴的喜爱。相比传统的膨化猫粮,主食冻干更符合猫咪的饮食天性,提供…

【Storm实战】1.1 图解Storm的抽象概念

文章目录 0. 前言1. Storm 中的抽象概念1.1 流 (Stream)1.2 拓扑 (Topology)1.3 Spout1.4 Bolt1.5 任务 (Task)1.6 工作者 (Worker) 2. 形象的理解Storm的抽象概念2.1 流 (Stream)2.2 拓扑 (Topology)2.3 Spout2.4 Bolt2.5 任务 (Task)2.6 工作者 (Worker)场景1场景2 3.参考文档…

如何打造家居产业数字化转型范式?林氏家居以数智供应链作答

近年来,我国房地产行业逐步进入深度调整期。作为下游产业,家居家装行业的发展也来到了新阶段。业内人士指出,新房市场成交规模收缩,家居家装企业们开始整合资源,向存量房市场、产品科技化以及数字化转型。 国家层面出…

教学/直播/会议触摸一体机定制_基于展锐T820安卓核心板方案

触控一体机是一种集先进的触摸屏、工控和计算机技术于一体的设备。它取代了传统的键盘鼠标输入功能,广泛应用于教学、培训、工业、会议、直播、高新科技展示等领域。触摸一体机的应用提升了教学、会议和展示的互动性和信息交流。 触摸一体机方案基于国产6nm旗舰芯片…

设置进程优先级

#include <windows.h>int main() {// 获取当前进程的句柄HANDLE hProcess GetCurrentProcess();// 设置当前进程的优先级为高SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS);// 执行其他代码return 0; }进程优先级 标志 idle &#xff08;低&#xff09; IDL…

Python (十七) __name__ == ‘__main__‘ 作用

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一波电子书籍资料&#xff0c;包含《Effective Java中文版 第2版》《深入JAVA虚拟机》&#xff0c;《重构改善既有代码设计》&#xff0c;《MySQL高性能-第3版》&…

小学副科老师轻松吗

在小学里&#xff0c;除了语文、数学和英语这些主科&#xff0c;还有许多副科老师&#xff0c;他们的工作日常是什么样的呢&#xff1f;今天&#xff0c;让我们一起来揭秘小学副科老师的一天。 备课&#xff1a;在忙碌中寻找创意的火花 副科老师同样需要花费大量时间进行备课…

视频剪辑指南:如何将多个视频快速批量合并的方法

在日常生活和工作中&#xff0c;经常要将多个视频片段合并为一个完整的视频。但是手动剪辑每个视频不仅费时&#xff0c;而且效率低下。那么如何解决这个问题呢&#xff0c;可以采用一些快速批量合并视频的方法。现在一起来看看云炫AI智剪如何批量合并视频的具体步骤吧。 合并…

Windows 使用 nmap软件测试 UDP 端口

下载windows版nmap &#xff0c;下载后双机默认安装。 Download the Free Nmap Security Scanner for Linux/Mac/Windows 打开CMD &#xff0c; 输入 cd C:\Program Files (x86)\Nmap C:\Program Files (x86)\Nmap>ncat -z -v -u ntp.aliyun.com 123 Ncat: Version 7.80 ( …

《现代C++语言核心特性解析》笔记(三)

二十四、三向比较&#xff08;C20&#xff09; 1. “太空飞船”&#xff08;spaceship&#xff09;运算符 C20标准新引入了一个名为“太空飞船”&#xff08;spaceship&#xff09;的运算符 <>&#xff0c;它是一个三向比较运算符。<> 之所以被称为“太空飞船”运…

六、HTML 段落

HTML 可以将文档分割为若干段落。 一、HTML 段落 段落是通过 <p> 标签定义的。 <p>这是一个段落 </p> <p>这是另一个段落</p> 注意&#xff1a;浏览器会自动地在段落的前后添加空行。&#xff08;</p> 是块级元素&#xff09; 二、不…

篮球羽毛球乒乓球体育场馆预订小程序开发

开发一款专业的小程序&#xff0c;用于多场馆场地的预定和管理&#xff0c;包括体育馆、羽毛球馆、兵乒球馆、篮球馆等各类场馆。此小程序旨在为场馆提供全方位的运营解决方案&#xff0c;并满足会员的不同需求。 该小程序的核心功能特性包括&#xff1a; 场馆管理&#xff…