Python教程(23)——Python类中常用的特殊成员

在Python中,类特殊成员是指以双下划线开头和结尾的属性和方法,也被称为魔术方法(Magic methods)或特殊方法(Special methods)。这些特殊成员在类的定义中具有特殊的语法和功能,用于实现对象的特定行为和操作。

特殊方法一般由Python解释器调用,无需手动调用。通过在类中定义这些特殊方法,可以改变对象的默认行为,使其具备更多的功能和操作。特殊方法提供了一种更加Pythonic的面向对象编程的方式,可以让代码更加简洁和易读。
在这里插入图片描述

__init__

__init__ 是Python中的一个特殊方法,也被称为构造方法。它在创建对象时自动调用,用于初始化对象的属性。通过在类中定义 __init__ 方法,我们可以在对象创建时为其赋予初始状态,设置属性的默认值,或执行其他必要的初始化操作。

__init__ 方法的格式通常如下:

def __init__(self, arg1, arg2, ...):self.attribute1 = arg1self.attribute2 = arg2# ...

self 代表对象本身,arg1arg2 等是用于接收传入的参数的形参,我们可以根据实际需要为 __init__ 方法传入不同的参数。

class Person:def __init__(self, name, age):self.name = nameself.age = ageperson1 = Person("Alittle", 30)

__init__ 方法中,我们可以执行其他的初始化操作,例如连接数据库、打开文件、设置默认值等。这使得我们能够在创建对象时,做一些必要的准备工作,确保对象在初始化后即可用。

需要注意的是,Python 中的 __init__ 方法是可选的,不是必须定义的。如果类中没有定义 __init__ 方法,Python 会使用默认的空的 __init__ 方法。但通常情况下,我们会定义 __init__ 方法来初始化对象的属性。

__del__

__del__ 是Python中的一个特殊方法,也被称为析构方法。它在对象被销毁前自动调用,用于进行清理工作。当对象的引用计数为零时(即没有任何变量引用该对象),Python解释器会自动触发 __del__ 方法的调用。

__del__ 方法的格式通常如下:

def __del__(self):# 清理代码

__del__ 方法中,self 代表对象本身。我们可以在 __del__ 方法中编写需要在对象销毁之前执行的清理代码,例如关闭文件、释放资源、记录日志等。

class FileHandler:def __init__(self, filename):self.file = open(filename, 'w')def write_data(self, data):self.file.write(data)def __del__(self):self.file.close()handler = FileHandler("data.txt")
handler.write_data("Hello, World!")
# 在退出程序或手动执行 del handler 时,会自动调用 __del__ 方法关闭文件

我们定义了一个 FileHandler 类,其中的 __init__ 方法用于打开文件并创建一个 file 对象。write_data 方法用于向文件写入数据。在 __del__ 方法中,我们通过 self.file.close() 关闭了文件。当程序退出或手动执行 del handler 时,对象 handler 被销毁,会自动调用 __del__ 方法关闭文件,确保资源的正常释放。

另外需要注意的是,__del__ 方法的调用是由Python解释器自动控制的,并不是我们手动调用的。因此,我们不能依赖 __del__ 方法来进行关键性的清理工作,如释放内存。一般来说,Python有自己的垃圾回收机制,会自动管理对象的内存释放。我们只需确保在 __del__ 方法中执行一些简单的清理操作即可。此外,应尽量避免在 __del__ 方法中抛出异常,以免影响其他代码的执行。

__str__

__str__ 也是Python中的一个特殊方法,也被称为字符串表示方法。它定义了当我们对一个对象使用内置的 str() 函数或 print() 函数进行输出时,应该返回的字符串形式表示。简而言之,__str__ 方法用于定制对象的字符串输出。

__str__ 方法的格式通常如下:

def __str__(self):# 返回表示对象的字符串

__str__ 方法中,self 代表对象本身,没有其他的参数了,我们可以在该方法中编写需要返回的表示对象的字符串形式的代码,例如组织对象的属性信息、状态等。

以下是一个示例,展示了如何使用 __str__ 方法来定制对象的字符串输出:

class Point:def __init__(self, x, y):self.x = xself.y = ydef __str__(self):print("call __str__")return f"Point({self.x}, {self.y})"p = Point(3, 4)
print(p)
print("-----------------")
str(p)

上面的示例中的输出

call __str__
Point(3, 4)
-----------------
call __str__

我们定义了一个 Point 类,其中的 __init__ 方法用于初始化点的坐标。在 __str__ 方法中,我们使用格式化字符串 f-string 将点的坐标表示为 ‘(x, y)’ 的形式。当我们对 p 对象使用 print(p)str(p) 时,会自动调用 __str__ 方法,并返回该方法中定义的字符串 (3, 4)

__repr__

__repr____str__ 方法类似,下面直接用一个例子来说明这个和 __str__ 的区别。

class Point:def __init__(self, x, y):self.x = xself.y = ydef __str__(self):print("call __str__")return f"Point1({self.x}, {self.y})"def __repr__(self):print("call __repr__")return f"Point2({self.x}, {self.y})"p = Point(3, 4)
print(p)
print("-----------------")
str(p)
repr(p)

上面的示例中的输出

call __str__
Point1(3, 4)
-----------------
call __str__
call __repr__

从上面的输出可以看出,repr(p) 函数可以自动调用 __repr__,默认情况下,__str____repr__ 同时存在的话,str()print()函数就会优先调用 __str__,而如果只有 __repr__ 的话,就会调用 __repr__,不信你们可以把上面例子中的 __str__ 注释掉,然后看看输出情况。

__len__

__len__ 用于定义对象的长度。它主要被用于内置函数 len() 的操作,用于返回一个对象的长度或元素的个数。

__len__ 方法的格式通常如下:

def __len__(self):# 返回对象的长度或元素的个数

__len__ 方法中,self 代表对象本身。我们可以在该方法中编写代码,返回一个整数,表示对象的长度或元素的个数。

以下是一个示例,展示了如何使用 __len__ 方法来定义一个自定义的容器类并使用 len() 函数获取其长度:

class MyContainer:def __init__(self):self.data = []def __len__(self):return len(self.data)def add(self, element):self.data.append(element)container = MyContainer()
container.add(1)
container.add(2)
container.add(3)print(len(container))  # 输出 3,调用了 __len__ 方法

在上面的示例中,我们定义了一个名为 MyContainer 的容器类,该类包含一个名为 data 的列表用于存储元素。在 __len__ 方法中,我们使用内置函数 len() 计算了 data 列表的长度,并返回该长度。当我们通过调用 len(container) 来获取 container 对象的长度时,实际上会自动调用 __len__ 方法,并返回该方法中定义的长度值。

__len__ 方法应该返回一个整数,表示对象的长度或元素的个数。如果一个类没有定义 __len__ 方法,或者 __len__ 方法返回的值不是整数类型,那么调用 len() 函数时会抛出 TypeError 异常。

__getitem__和__setitem__

__getitem____setitem__ 几乎都是成对出现的,__getitem__ 用于定义对象的索引操作,即允许通过索引值访问对象的元素,__setitem__ 用于定义对象的赋值操作,即允许通过索引值设置对象的元素值,它主要用于支持下标操作和切片操作。

__getitem____setitem__ 方法的格式通常如下:

def __getitem__(self, index):# 返回指定索引位置的元素def __setitem__(self, index, value):# 设置指定索引位置的元素为指定的值

这两个方法一个就是取值,一个就是赋值,主要就是应用在对象上面,相对而言比较好理解。

class MyList:def __init__(self):self.data = []def __getitem__(self, index):return self.data[index]def __setitem__(self, index, value):self.data[index] = valuemylist = MyList()
mylist.data = [1, 2, 3, 4, 5]print(mylist[2])  # 输出 3,调用了 __getitem__ 方法
mylist[2] = 10  # 调用了 __setitem__ 方法赋值
print(mylist[2])  # 输出 10,调用了 __getitem__ 方法

在上面的示例中,我们定义了一个名为 MyList 的列表类,该类包含一个名为 data 的列表用于存储元素。通过实现 __getitem____setitem__方法,我们可以使用类似于列表的方式通过索引来访问和设置 data 列表中的元素。
__getitem__ 方法通常与 __setitem__ 方法一起使用,以支持对象的索引和切片操作。通过定义这些方法,我们可以使自定义的类对象能够像内置的容器类型一样进行元素的访问和修改。

如果一个类没有定义 __getitem____setitem__方法,或者__getitem____setitem__方法不能处理给定的索引值或切片对象,那么当我们尝试通过索引或切片来访问(设置)对象时,会抛出 TypeError 异常。

__call__

__call__ 用于使对象能够像函数一样被调用。通过定义 __call__ 方法,我们可以将一个对象变成一个可调用的实例,类似于函数的行为。

__call__ 方法的格式通常如下:

def __call__(self, *args, **kwargs):# 定义对象的调用逻辑

__call__ 方法中,self 代表对象本身,argskwargs 是传递给对象调用时的参数。

当我们像调函数一样使用对象时,Python 解释会自动调用对象的 __call__ 方法,并将传入的参数作为参数递给该方法。我们可以在 __call__ 方法中定义对象的调用逻,然后执行相应的操作。

以下一个示例,展示了如何使用 __call__ 方法来定义一个可调用的对象:

class Adder:def __call__(self, x, y):return x + yadd = Adder()# 将对象 add 当作函数进行调用
result = add(3, 5)
print(result)  # 输出:8

在上述示例中,我们定义了一个 Adder 类,并实现了 __call__ 方法。在该方法中,我们将传入的两个参数进行相加,Python 解释器会自动调用对象 add__call__ 方法,并将传递给该方法。__call__ 方法中的逻辑会被执行,参数进行相加操作,然后返回结果。

通过使用 __call__ 方法,我们可以将一个对象实例化后,即可像函数一样进行调用,并执行预定义的逻辑。这样可以增加对象的灵活性,使其更加接近函数的行为。__call__ 方法只有在对象被调用时才会被调用,也就是对象被函数那样调用。

通常情况下,__call__ 方法常用于实现可调用的对象,如自定义的函数对象、装饰器、上下文管理器等。通过定义 __call__ 方法,我们可以使对象具有函数的特性,并能够直接调用执行相应的逻辑。

更多精彩内容,请关注同名公众:一点sir(alittle-sir)

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

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

相关文章

【PlantUML】-类图-布局,如何改变元素位置

写在前面 PlantUML属于自动布局。掌握好,是一件利器,掌握不好,就会不知其所以然。尤其在布局方面,因为它的布局可能会和你想的不太一样。本篇文章以例子为基础,简单地说几个在实际应用过程中摸索出来的原则。相信看完这…

【猫头虎分享】全面揭秘鸿蒙4.0:华为的技术革新与市场影响

博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通Golang》…

逆变器3前级推免(高频变压器)

一节电池标压是在2.8V—4.2V之间,所以24V电压需要大概七节电池串联。七节电池电压大概在19.6V—29.4V之间。 从24V的电池逆变到到220V需要升压的过程。那么我们具体需要升压到多少? 市电AC220V是有效值电压,峰值电压是220V*1.414311V 如果…

ssm基于Javaweb的物流信息管理系统的设计与实现论文

摘 要 如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统物流信息管理难度大,容错率低,管理…

数据结构——排序算法之快速排序

个人主页:日刷百题 系列专栏:〖C/C小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 🌎欢迎各位→点赞👍收藏⭐️留言📝 ​ ​ 前言: 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法。 基本思想&…

opencv-4.8.0编译及使用

1 编译 opencv的编译总体来说比较简单,但必须记住一点:opencv的版本必须和opencv_contrib的版本保持一致。例如opencv使用4.8.0,opencv_contrib也必须使用4.8.0。 进入opencv和opencv_contrib的github页面后,默认看到的是git分支&…

NAS搭建NextCloud集成OnlyOffice

1、安装NextCloud(如果总是中断就换个镜像源) 2、创建容器 如果需要穿透选HOST 端口必须80 读写必须开 3、启动容器并配置,看图。 启动看日志,等启动完成再访问。首次启动大约5-10分钟左右。 成功后,我们正常进行安装…

学习selenium+python使用 XPath 表达式来实现找到目标元素时智能封装等待,执行测试代码启动Chrome浏览器后,地址栏只显示data;

背景 学习使用 XPath 表达式来实现找到目标元素时智能封装等待执行测试代码启动Chrome浏览器后,地址栏只显示data; 代码如下 import unittest from selenium import webdriver from selenium.common.exceptions import NoSuchElementException from …

6.2 声音编辑工具GoldWave5简介(5)

6.2.4录制声音 利用Windows自带的“录音机”录制声音时,只能录制最大时长为1分钟的声音,而利用GoldWave5,可以录制时长长达277小时以上的声音,而且,录制完成后,还可以很方便地对声音进行处理、转换等操作。…

记录用python封装的第一个小程序

前言 我要封装的是前段时间复现的一个视频融合拼接的程序,现在我打算将他封装成exe程序,我在这里只记录一下我封装的过程,使用的是pyinstaller,具体的封装知识我就不多说了,可以参考我另一篇博客:将Python…

NLP技术在搜索推荐场景中的应用

NLP技术在搜索推荐中的应用非常广泛,例如在搜索广告的CTR预估模型中,NLP技术可以从语义角度提取一些对CTR预测有效的信息;在搜索场景中,也经常需要使用NLP技术确定展现的物料与搜索query的相关性,过滤掉相关性较差的物…

力扣2182.构造限制重复的字符串

思路:先记录每个字符的出现次数,构建一个新字符串,从尾取字符,每取一个该字符个数-1,若该字符已经取到有repeatLimit个,则递归取次大的字符,并对应字符个数-1,若没有次大字符了&…

Elasticsearch基础篇(七):分片大小修改和路由分配规则

Elasticsearch基础篇(七):分片大小修改和路由分配规则1. 分片1.1 主分片(Primary Shard)1.2 副本分片(Replica Shard)1.3 分片路由(Routing Shard) 2. 分片分配的基本策略3. 分片写入验证3.1 数…

2024年前端最新面试题-vue3(持续更新中)

文章目录 前言正文什么是 MVVC什么是 MVVM什么是 SPA什么是SFC为什么 data 选项是一个函数Vue 组件通讯(传值)有哪些方式Vue 的生命周期方法有哪些如何理解 Vue 的单项数据流如何理解 Vue 的双向数据绑定Vue3的响应式原理是什么介绍一下 Vue 的虚拟 DOM介…

设计模式-- 3.适配器模式

适配器模式 将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 角色和职责 请求者(client):客户端角色,需要使用适配器的对象,不需要关心适配器内部的实现,…

常用的检测数据异常值方式,以及异常数据如何处理!!

清除数据异常值 1.箱线图检测数据异常值方法2.3σ原则检测数据异常值方法3. 异常数据处理方式:总结(小白看看就行) 1.箱线图检测数据异常值方法 箱线图检测:箱线图是一种常用的异常值检测方法,它以数据的分位数为基础…

常见的加密算法

加密算法 AES 高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图: RSA RSA 加密算法是一种典型的非对称加密算法&am…

Java后端开发——Mybatis实验

文章目录 Java后端开发——Mybatis实验一、MyBatis入门程序1.创建工程2.引入相关依赖3.数据库准备4.编写数据库连接信息配置文件5.创建POJO实体6.编写核心配置文件和映射文件 二、MyBatis案例:员工管理系统1.在mybatis数据库中创建employee表2.创建持久化类Employee…

嵌套的CMake

hehedalinux:~/Linux/multi-v1$ tree . ├── calc │ ├── add.cpp │ ├── CMakeLists.txt │ ├── div.cpp │ ├── mult.cpp │ └── sub.cpp ├── CMakeLists.txt ├── include │ ├── calc.h │ └── sort.h ├── sort │ ├── …

基于面向对象编程,C++实现单链表

链表:在内存空间中是非连续存储 组成:链表是由一个个节点组成的,每个节点都包含两个元素:数据和指针 节点头文件: 建立一个ListNode.h头文件 #pragma once class ListNode { public:int value;ListNode* next;Lis…