python中类class的魔法方法

开始介绍之前,我们先看下之前文章我们介绍过的内置类merryview的一些方法,如下图所示: 有很多双下划线开始和结束的method,这么多method是做啥子用的呢?

其实这些方法就是我们常说的魔法方法,也是python中的特殊方法。它们以双下划线 __ 开始和结束,这些方法为 Python 类提供了丰富的功能。

以下开始介绍下常见的魔法方法:

1 构造方法

构造方法有__new__ __init__ __del__

__new__:如果设置了该方法,当我们定义类的实例时,该方法会被第一个调用,而不是先调用__init__方法。该方法需要返回一个类的实例。

__init__: 初始化类的实例属性,并可在该方法中定义其他一些属性或者调用其他函数等作为初始化的功能。

__del__: 当类实例对象销毁时会自动调用该方法。

举例:定义一个类,并做类的实例化

class Car(object):def __init__(self,brand,color,cost_performance):print('__init__被调用')self.brand = brandself.color = colorself.cost_performance = cost_performancedef __new__(cls, *args, **kwargs):print('__new__被调用')def __del__(self):print('__del__被调用')

实例化类:

car_ins = Car('BYD','black','high')
print(car_ins.brand)

当执行时,发现报错如下:只有__new__方法被调用了,而没有调用__init__,所以在打印实例属性时报错。

原因是__new__方法中没有返回对象实例。

我们在__new__方法中添加如下一行代码:super().__new__(cls)

def __new__(cls, *args, **kwargs):print('__new__被调用')return super().__new__(cls)

再次实例化类的时候

car_ins = Car('BYD','black','high')
print(car_ins.brand)

打印结果如下:

__new__被调用
__init__被调用
BYD
__del__被调用

解释:增加的这一行super().__new__(cls)作用就是调用基类object创建一个实例并返回,有了实例然后再调用__init__ 方法做初始化。当程序执行完成后,实例对象的内存会被释放,然后自动调用__del__方法。

2 类的表示方法

类的表示方法主要有__repr__ __str__

  1. __str__:当使用print函数打印对象实例或者str函数转换对象实例时,会调用该方法返回的字符串,如果没有该方法会继续找__repr__方法中的字符串信息
  2. __repr__:当使用repr函数打印对象实例时,会调用该方法返回的字符串,如果没有该方法会继续找__str_方法中的字符串信息

举例:

class Car(object):def __init__(self,brand,color,cost_performance):print('__init__被调用')self.brand = brandself.color = colorself.cost_performance = cost_performancedef __str__(self):print('__str__被调用')return '我是Car类'def __repr__(self):print('__repr__被调用')return '我是Car类'

类实例化后,打印下类实例:

car_ins = Car('BYD','black','high')
print(car_ins)
print(str(car_ins))
print(repr(car_ins))

结果:

__str__被调用
我是Car类
__str__被调用
我是Car类
__repr__被调用
我是Car类

3 上下文管理器方法

通过定义一个类,并实现__enter__()和__exit__()方法,那么这个类就可以被称为上下文管理器,也就可以使用with as的语句。

__enter__()方法:返回一个值,可以将它赋值给with...as后面的对象。

__exit__()方法: with...as 语句退出或者发送异常时会执行这个方法。

比如之前我们的文章讲到open函数我们经常会用到上下文管理器:

with open('test.txt','r') as fd:content = fd.readlines ()

4 可迭代对象和迭代器方法

方法有 __iter__ __next__

  • 可迭代对象:指python中可以用来迭代(支持for循环)的对象,比如常见的列表/元组/字典/字符串等,这些对象中都会定义__iter__魔法方法。
  • 迭代器:指可以帮助我们迭代其他对象的一种对象。这类对象会定义__next__魔法方法,可通过next()函数获取迭代的结果。

可迭代对象不一定是迭代器,但迭代器肯定是可迭代对象。因为迭代器要求必须同时实现__iter__方法和__next__方法, 而一旦实现了__iter__方法就必然是一个可迭代对象。但是反过来则不成立,可迭代对象可以不是迭代器。

1)判断对象是可迭代对象和迭代器

在python模块中先导入Iterable和Iterator。

from typing import Iterable,Iterator
或者
from collections.abc import Iterable,Iterator

通过isinstance(Object, Iterable)可判断一个对象是否是可迭代对象

通过isinstance(Object, Iterator)可判断一个对象是否是迭代器

2)常见的列表等是可迭代对象,但不是迭代器。

#定义一个列表
listA = [1,4,3,2]
print(f'列表是否是迭代对象 :{isinstance(listA,Iterable)}')
print(f'列表是否是迭代器 {isinstance(listA,Iterator)}')
#结果:
列表是否是迭代对象 :True
列表是否是迭代器 False

python安装好后有个自带的模块builtins.py,找到定义的list类,会发现该类中定义了__iter__方法,没有定义__next__方法。

class list(object):"""Built-in mutable sequence.If no argument is given, the constructor creates a new empty list.The argument must be an iterable if specified."""def append(self, *args, **kwargs): # real signature unknown""" Append object to the end.....def __iter__(self, *args, **kwargs): # real signature unknown""" Implement iter(self). """pass

使用next()执行列表会报错列表不是一个迭代器。

next(listA)
#会报错如下
Traceback (most recent call last):
File "test.py", line 9, in <module>
next(listA)
TypeError: 'list' object is not an iterator

3)使用iter()将可迭代对象转换为迭代器

还是以上面的列表举例,使用iter()将列表转换为迭代器。

list_iter = iter(listA)
print(f'列表使用iter()后是否是迭代对象 :{isinstance(list_iter,Iterable)}')
print(f'列表使用iter()是否是迭代器 {isinstance(list_iter,Iterator)}')
#打印结果
列表使用iter()后是否是迭代对象 :True
列表使用iter()是否是迭代器 True

5 容器方法

容器方法主要有__len__ __getitem__ __setitem__ __delitem__ __contains__ __reversed__

  • __len__(self ): 获取容器中元素的数量,配合len() 函数使用。
  • __getitem__(self, index): 获取容器中的元素值,index表示容器中的索引。
  • __setitem__(self, index, value): 设置容器中的元素值,index表示容器中的索引,value表示要设置的值。
  • __delitem__(self, index): 删除容器中的元素,index表示容器中的索引。
  • __contains__(self, item): 判断容器中是否包含某个元素,使用in 判断。
  • __reversed__(self): 当使用reversed() 内建函数会调用该方法,定义为返回一个反转之后的序列。

举例:自定义一个列表对象,并初始化一个传入的列表

class MyList(object):def __init__(self,newlist):self.newlist = newlistdef __len__(self):print('使用了__len__')return len(self.newlist)def __getitem__(self,index):print('使用了__getitem__')return self.newlist[index]def __setitem__(self, index, value):print('使用了__setitem__')self.newlist[index] = valuedef __delitem__(self, index):print('使用了__delitem__')del self.newlist[index]def __contains__(self, item):print('使用了__contains__')return item in self.newlistdef __reversed__(self):print('使用了__reversed__')return reversed(self.newlist)

对自定义列表对象进行增删改查时,会用到上述魔法方法:

先初始化实例:

mylist1 = MyList([1,2,3,4,5])

1)获取元素个数:

print(f'初始元素个数:{len(mylist1)}')

结果:

使用了__len__
初始元素个数:5

2)获取元素值

print(f'index为1的值:{mylist1[1]}')

结果:

使用了__getitem__
index为1的值:2

3)设置元素值

mylist1[0] = 100
print(f'index为0的值:{mylist1[0]}')

结果:

使用了__setitem__
使用了__getitem__
index为0的值:100

4)删除元素的值

del mylist1[-1]
print(f'删除最后一个元素后列表为:{list(mylist1)}')

结果:

使用了__delitem__
使用了__len__
使用了__getitem__
使用了__getitem__
使用了__getitem__
使用了__getitem__
使用了__getitem__
删除最后一个元素后列表为:[100, 2, 3, 4]

5)判断是否包含某个元素

print(f'判断数字2是否在列表内:{2 in mylist1}')

结果:

使用了__contains__
判断数字2是否在列表内:True

6)反转序列

print(list(reversed(mylist1)))

结果:

使用了__reversed__
[4, 3, 2, 100]

6 比较方法

比较方法主要有__eq__ __lt__ __le__ __gt__ __ge__ __ne__

  • __eq__(self, other):定义等于操作符(==)的行为。
  • __ne__(self, other):定义不等于操作符(!=)的行为。
  • __lt__(self, other):定义小于操作符(<)的行为。
  • __gt__(self, other):定义大于操作符(>)的行为。
  • __le__(self, other):定义小于等于操作符(<=)的行为。
  • __ge__(self, other):定义大于等于操作符(>=)的行为。

举例:定义一个类,初始化时随机生成一个整数。

import random
class rnum(object):def __init__(self,num):self.num = random.randint(0,num)def __eq__(self,other:int):print('使用了__eq__')return self.num == otherdef __le__(self,other:int):print('使用了__getitem__')return self.num <= otherdef __ge__(self, other:int):print('使用了__ge__')return self.num >= otherdef __lt__(self, other:int):print('使用了__lt__')return self.num < otherdef __gt__(self, other:int):print('使用了__gt__')return self.num > otherdef __ne__(self,other:int):print('使用了__ne__')return self.num != other

初始化类,传入数字10,并将对象做比较运算。

newnum = rnum(10)
print(f'newnum.num = {newnum.num}')
#比较对象值的数字7的大小
print(f'判断== : {newnum == 7}')
print(f'判断>= : {newnum >= 7}')
print(f'判断>= : {newnum >= 7}')
print(f'判断< : {newnum < 7}')
print(f'判断> : {newnum > 7}')
print(f'判断!= : {newnum != 7}')

#结果:

newnum.num = 1
使用了__eq__
判断== : False
使用了__ge__
判断>= : False
使用了__ge__
判断>= : False
使用了__lt__
判断< : True
使用了__gt__
判断> : False
使用了__ne__
判断!= : True

7 算术方法

常用到的算术方法如下:

__add__(self, other):实现加法+操作。

__sub__(self, other):实现减法-操作。

__mul__(self, other):实现乘法*操作。

__floordiv__(self, other):实现使用//操作符的整数除法。

__div__(self, other):实现使用/操作符的除法。

__mod__(self, other):实现%取余操作。

__divmod__(self, other):实现 divmod 内建函数。__pow__:实现冥运算**操作

__lshift__(self, other):实现左移位运算符<<。

__rshift__(self, other):实现右移位运算符>>。

__and__(self, other):实现按位与运算符&。

__or__(self, other):实现按位或运算符|。

__xor__(self, other):实现按位异或运算符^。

举例:定义一个类,初始化时随机生成一个整数。

import random
class rnum(object):def __init__(self,num):self.num = random.randint(0,num)def __add__(self,other:int):print('使用了__add__')return self.num + otherdef __sub__(self,other:int):print('使用了__sub__')return self.num - otherdef __mul__(self, other:int):print('使用了__mul__')return self.num * otherdef __floordiv__(self, other:int):print('使用了__floordiv__')return self.num // otherdef __mod__(self,other:int):print('使用了__mod__')return self.num % otherdef __divmod__(self,other:int):print('使用了__divmod__')return divmod(self.num,other)def __pow__(self,other:int):print('使用了__pow__')return self.num ** otherdef __lshift__(self,other:int):print('使用了__lshift__')return self.num << otherdef __rshift__(self,other:int):print('使用了__rshift__')return self.num >> otherdef __and__(self,other:int):print('使用了__and__')return self.num & otherdef __or__(self,other:int):print('使用了__or__')return self.num | otherdef __xor__(self,other:int):print('使用了__xor__')return self.num ^ other

初始化类,并计算如下:

1)按数值计算

newnum = rnum(100)
print(f'newnum.num = {newnum.num}')
print(f'加法: {newnum + 3}')
print(f'减法 : {newnum - 3}')
print(f'乘法 : {newnum * 3}')
print(f'//除法 : {newnum // 3}')
print(f'计算余数 : {newnum % 3}')
print(f'计算商和余数 : {divmod(newnum,3)}')
print(f'计算冥次 : {newnum ** 3}')

#结果

newnum.num = 41
使用了__add__
加法: 44
使用了__sub__
减法 : 38
使用了__mul__
乘法 : 123
使用了__floordiv__
//除法 : 13
使用了__mod__
计算余数 : 2
使用了__divmod__
计算商和余数 : (13, 2)
使用了__pow__
计算冥次 : 68921
2)按位进行计算:指转换为2进制后的一些计算
print(f'计算左移<< : {newnum << 3}')
print(f'计算右移>> : {newnum >> 3}')
print(f'计算位与& : {newnum & 3}')
print(f'计算位或| : {newnum | 3}')
print(f'计算位异或^ : {newnum ^ 3}')

#结果

使用了__lshift__
计算左移<< : 328
使用了__rshift__
计算右移>> : 5
使用了__and__
计算位与& : 1
使用了__or__
计算位或| : 43
使用了__xor__
计算位异或^ : 42

解释按位计算的示例:

print(f'数字41的2进制数:{bin(41)}')
print(f'2进制转为10进制数:{int("0b101001",base=2)}')#0b101001 整体往左移3位变成0b101001000
print(f'2进制转为10进制数:{int("0b101001000",base=2)}')#0b101001 整体往右移3位变成0b101
print(f'2进制转为10进制数:{int("0b101",base=2)}')#0b101001 与数字3(0b11) 做&的运算 得到0b000001
print(f'2进制转为10进制数:{int("0b000001",base=2)}')#0b101001 与数字3(0b11) 做|的运算 得到0b101011
print(f'2进制转为10进制数:{int("0b101011",base=2)}')#0b101001 与数字3(0b000011) 做^的运算 得到0b101010
print(f'2进制转为10进制数:{int("0b101010",base=2)}')

结果:跟上面按位运算的结果一致

数字41的2进制数::0b101001
2进制转为10进制数::41
2进制转为10进制数::328
2进制转为10进制数::5
2进制转为10进制数::1
2进制转为10进制数::43
2进制转为10进制数::42

补充知识:

  • 按位左移:将一个数的各二进制位全部左移若干位,右边多出的位将用0填充。
  • 按位右移:将一个数的各二进制位全部右移若干位,左边多出的位将用0填充。
  • 按位与:只有当两个对应位都为1时,结果才为1,否则结果为0
  • 按位或:只要有一个对应位为1时,结果就为1,都为0时结果为0
  • 按位异或:相同为0,不同为1:如果两个比较的位相同,则结果为0;如果不同,则结果为1。

8 属性方法

关于属性相关的有以下方法:

__dir__(self):定义对类的实例调用 dir() 时的行为,返回一个属性列表。

__getattr__(self,name):当用户试图访问一个不存在的属性时,会调用该方法。

__setattr__(self,name,value):自定义某个属性的赋值时调用该方法。

__delattr__(self,name):删除某个属性时调用该方法。

举例:定义一个类以及上面的方法

class Car(object):def __init__(self,brand,color,cost_performance):print('__init__被调用')self.brand = brandself.color = colorself.cost_performance = cost_performancedef __dir__(self):print('__dir__被调用')return ['brand','color','cost_performance']def __getattr__(self, name):print('__getattr__被调用')return self.__dict__.get(name)def __setattr__(self,name,value):print('__setattr__被调用')self.__dict__[name] = valuedef __delattr__(self,name):print('__delattr__被调用')del self.__dict__[name]

类实例化

car_ins = Car('BYD','black','high')

1)返回实例的属性列表

print(dir(car_ins))

结果:

__dir__被调用
['brand', 'color', 'cost_performance']

2)返回实例的属性字典

print(car_ins.__dict__)

结果:

{'brand': 'BYD', 'color': 'black', 'cost_performance': 'high'}

3)获取某个属性

print(car_ins.other)

结果:因为没有该属性,所以返回为None

__getattr__被调用
None

4)设置属性

car_ins.other = 'xxx'
print(car_ins.__dict__)

结果:

__setattr__被调用
{'brand': 'BYD', 'color': 'black', 'cost_performance': 'high', 'other': 'xxx'}

5)删除属性

del car_ins.other
print(car_ins.__dict__)

结果:

__delattr__被调用
{'brand': 'BYD', 'color': 'black', 'cost_performance': 'high'}

共勉: 东汉·班固《汉书·枚乘传》:“泰山之管穿石,单极之绠断干。水非石之钻,索非木之锯,渐靡使之然也。”

-----指水滴不断地滴,可以滴穿石头;

-----比喻坚持不懈,集细微的力量也能成就难能的功劳。

----感谢读者的阅读和学习和关注,谢谢大家。

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

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

相关文章

力扣——3143.正方形中的最多点数

题目&#xff1a; 自己的题解&#xff08;史&#xff09;&#xff1a; PS&#xff1a;自己看了好几遍才看懂题目&#xff0c;然后想看题解&#xff0c;但是又看到了“标签”是 于是靠着自己效率极低的写了出来。 思路&#xff1a;二分 首先利用map&#xff0c;将每个坐标和标…

Es6常用的一些数组处理方法

在平时的开发中&#xff0c;我们很多时候用到数组结构数据&#xff0c;那么如何高效处理数组是可以提高开发效率的&#xff0c;现在越来越多人使用es6&#xff0c;那么它的很多方法简化了我们对数据的操作&#xff0c;比如以前数组循环用for循环写比较多的代码&#xff0c;现在…

20 注意力机制—注意力机制在seq2seq

1.使用注意力机制的seq2seq 注意力机制在 NLP 中的应用,也是最早的工作之一动机 在机器翻译的时候,每个生成的词可能相关于源句子中不同的词在语言翻译的时候,中文和英文之间的翻译可能会存在倒装,但是可能在西方语言之间,相同意思的句子中的词的位置可能近似地是对应的,…

Linux命令用法

文章目录 前言一、Linux基础命令1. Linux目录结构2. Linux命令入门3. 目录切换相关命令&#xff08;cd、pwd&#xff09;4. 相对路径、绝对路径和特殊路径符5. 创建目录命令&#xff08;(mkdir&#xff09;6. 文件操作命令part1(touch、cat、more&#xff09;7. 文件操作命令pa…

端侧模型与端到端模型,两者是一个东西吗

端侧模型 专为在端侧设备上运行而设计的人工智能模型&#xff0c;它们通常具有较小的模型参数量&#xff0c;以适应端侧设备的计算能力和内存限制。端侧模型可以快速响应&#xff0c;保护用户隐私&#xff0c;并且无需依赖云端算力&#xff0c;因此在消费电子产业中具有重要的…

学习记录——day25 多线程编程 临界资源 临界区 竞态 线程的同步互斥机制(用于解决竟态)

目录 ​编辑 一、多进程与多线程对比 二、 临界资源 临界区 竞态 例1&#xff1a;临界资源 实现 输入输出 例2&#xff1a;对临界资源 进行 减减 例子3&#xff1a;临界资源抢占使用 三、线程的同步互斥机制&#xff08;用于解决竟态&#xff09; 3.1基本概念 3.2线…

C# 实现改造 GooFlow 流程图插件与数据库应用的结合

目录 关于 GooFlow 功能需求 范例运行环境 设计数据表 流程项目表 流程项目节点明细表 流程项目节点审批人表 人员信息表 示例代码 流程图主功能 设置审批人信息 运行结果演示 总结 关于 GooFlow GooFlow 一个基于 Jquery/FontAwesome 的流程图/架构图画图插件&…

Spring File Storage(文件的对象存储)框架基本使用指南

概述 本文仅作为快速入门&#xff0c;深入学习及使用详见官网 云存储 在开发过程当中&#xff0c;会使用到存文档、图片、视频、音频等等&#xff0c;这些都会涉及存储的问题&#xff0c;文件可以直接存服务器&#xff0c;但需要考虑带宽和存储空间&#xff0c;另外一种方式…

漏洞挖掘 | src中一次证书站有趣的SQL注入

一、确定站点 按照以前文章中提到的寻找可进站测试的思路&#xff0c;找到了某证书站的一处站点&#xff0c;通告栏中写明了初始密码的结构&#xff0c;因此我们可通过信息搜集进入该站点(可以考虑去搜集比较老的学号&#xff0c;因为这样的账号要么被冻结&#xff0c;要么就是…

AMD Product Specifications - AMD 产品规格汇总

AMD Product Specifications - AMD 产品规格汇总 1. Desktop, Laptop and Workstation Processor Specifications (台式处理器、笔记本电脑处理器和工作站处理器规格)2. Server Processor Specifications (服务器处理器规格)3. Embedded Processor Specifications (嵌入式处理器…

土耳其射击运动员尤素夫迪凯克在巴黎奥运会上成为互联网热门人物

这名51岁的男子以自己的方式获得了第二名,这对他的祖国来说是一个历史性的时刻。 这位冷静沉着的土耳其手枪射击运动员周二在 2024 年巴黎奥运会上获得银牌&#xff0c;在网上吸引了众多粉丝。 尤素夫迪克与他的搭档塞夫瓦尔伊莱达塔尔汉在混合团体 10 米气手枪比赛中获得第二…

jupyter notebook安装

1.安装 pip install notebook 2.显示配置文件&#xff1a; jupyter notebook --generate-config 3.修改代码路径&#xff1a; 编辑配置文件C:\Users\a\.jupyterjupyter_notebook_config.py 4.运行 jupyter notebook 会自动弹出http://localhost:8888/tree

QT 笔记

HTTPS SSL配置 下载配置 子父对象 QTimer *timer new QTimer; // QTimer inherits QObject timer->inherits("QTimer"); // returns true timer->inherits("QObject"); // returns true timer->inherits("QAbst…

保形分位数回归(CQR)

目录 简介1 介绍提纲式总结 分位数回归从数据中估计分位数 3 共性预测4 保形分位数回归(CQR)两个定理 6 实验7 结论 简介 保形预测是一种构造在有限样本中获得有效覆盖的预测区间的技术&#xff0c;无需进行分布假设。尽管有这种吸引力&#xff0c;但现有的保形方法可能是不必…

【文心智能体】梗图七夕版,一分钟让你看懂如何优化prompt,以及解析低代码工作流编排实现过程和零代码结合插件实现过程,依然是干货满满,进来康康吧

目录 背景什么是梗图梗图概念梗图结构 低代码开发最小运行单元大模型链提示词模板文心模板输出效果 测试工具链HTTP请求工具 梗图工具链全流程 梗图优化Prompt提示词优化后梗图结构提示词前后对比优化前效果优化后效果API接口BOS图片水印 梗图插件格式说明构思插件清单文件定义…

HTML-07.表格标签

一、要制作的表格如下 二、代码如下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>表格标签<…

数据结构——双链表详解(超详细)

前言&#xff1a; 小编在之前已经写过单链表的创建了&#xff0c;接下来要开始双链表的讲解了&#xff0c;双链表比单链表要复杂一些&#xff0c;不过确实要比单链表更好进行实现&#xff01;下面紧跟小编的步伐&#xff0c;开启今天的双链表之旅&#xff01; 目录 1.概念和结构…

【已解决】没有密码,如何解除PPT的“只读方式”?

PPT可以设置有密码的“只读方式”&#xff0c;保护文件不被随意编辑更改。 在设置保护后&#xff0c;打开PPT时就会弹出对话框&#xff0c;提示需要“输入密码以修改或以只读方式打开”&#xff0c;也就是输入密码才能编辑修改PPT&#xff0c;如果点击“只读”也能打开文件&am…

[BJDCTF2020]Mark loves cat1

打开题目 发现这么多链接&#xff0c;以为要一点点去找功能上的漏洞。当你源代码&#xff0c;dirsearch&#xff0c;抓包等等操作之后&#xff0c;发现什么都没有。所以这题又是一道源码泄露题&#xff0c;上GItHack。扫描结果如下 http://63f29a80-e08b-43ae-a6d0-8e70fb02ea…

闪耀STIF2023国际科创节,望繁信科技荣获年度行业创新典范奖

2023年12月15日&#xff0c;望繁信科技在STIF2023第四届国际科创节暨DSC2023国际数字服务大会&#xff08;数服会&#xff09;活动评选中&#xff0c;斩获“2023年度行业创新典范”大奖。 作为科技创新与数字化服务领域最具影响力的年度盛会之一&#xff0c;STIF2023国际科创节…