[Python进阶] 定制类:运算篇

news/2024/10/21 6:03:28/

4.10.4 运算篇

Python的类型系统是鸭子类型,也就是不检查某个具体的对象是什么类型,而是检查这个对象有没有相应的功能。在Python中有大量的魔术方法,我们可以通过魔术方法的方式为对象添加相应的功能。
下面介绍Python中和运算相关的魔术方法。这些魔术方法是对两个对象在进行符号运算时对相应的运算符号进行重载,从而实现相应的效果。
在本篇所讲的运算相关的魔术方法中,参数other并不一定要和self一致。
很多时候我们用魔术方法,只是借用了这个符号,并不一定要符号该符号原来的定义。比如:我们可以将<<左移符号重载成C++中的cout。

4.10.4.1 add

add:obj1 + obj2

from icecream import icclass Vector:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f'Vertor({self.x}{self.y})'def __add__(self, other):return Vector(self.x + other.x, self.y + other.y)v1 = Vector(0, 1)
v2 = Vector(2, 3)
print(v1 + v2)

Vertor(2,4)

4.10.4.2 sub

sub:obj1 – obj2

4.10.4.3 mulmatmulpow

mul:obj1 * obj2
matmul:obj1 @ obj2
pow:obj1 ** obj2、pow(obj1, obj2, mod=None)  (obj1 ** obj2) % mod

4.10.4.4 truedivfloordivmoddivmod

truediv:obj1 / obj2
floordiv:obj1 // obj2
mod:obj1 % obj2
divmod:divmod(obj1,obj2)

4.10.4.5 lshiftrshift

lshift:obj1 << obj2
rshift:obj1 >> obj2

4.10.4.6 andxoror

and:obj1 & obj2
xor:obj1 ^ obj2
or:obj1 | obj2

4.10.4.7 运算符的r版本

如下代码所示,当我们自定义乘法,判断相乘的对象是int类型时,则将x,y同时和int相乘并返回。但是,如果是int类型数据和我们自定义的Vector类型相乘时,则会报错,因为是Python内置的int类型是不知道要如何和我们自定义的Vector类型相乘的。

from icecream import icclass Vector:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f'Verctor({self.x}{self.y})'def __mul__(self, other):# v1 * v2if isinstance(other, int):return Vector(self.x * other, self.y * other)v1 = Vector(2, 3)
ic(v1 * 2)  # 本质:v1.__mul__(2)
ic(2 * v1)

ic| v1 * 2: Verctor(4,6)
Traceback (most recent call last):
File “E:\BaiduSyncdisk\FrbPythonFiles\t2.py”, line 20, in
ic(2 * v1)
TypeError: unsupported operand type(s) for *: ‘int’ and ‘Vector’

解决办法是定义一个__rmul__魔法方法,如下:

from icecream import icclass Vector:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f'Verctor({self.x}{self.y})'def __mul__(self, other):# v1 * v2if isinstance(other, int):return Vector(self.x * other, self.y * other)def __rmul__(self, other):# v1 * v2if isinstance(other, int):return Vector(self.x * other, self.y * other)v1 = Vector(2, 3)
ic(v1 * 2)
ic(2 * v1)

ic| v1 * 2: Verctor(4,6)
ic| 2 * v1: Verctor(4,6)

这样一来,如果操作符左侧的这个数据结构没有定义这个操作应该怎么完成的话,Python就会尝试去找操作符右侧这个对象的操作符的r版本魔法方法。这样就可以正常完成int * Verctor的操作了。
这里,之前列出的所有和数的计算有关的魔法方法都有其r版本。

4.10.4.8 运算符的i版本

i版本运算符魔法方法最后是修改self并返回。其实对应的符号就是操作符=。比如:v1 += v2就会调用:v1.iadd(v2)。

from icecream import icclass Vector:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f'Vertor({self.x}{self.y})'def __add__(self, other):return Vector(self.x + other.x, self.y + other.y)def __iadd__(self, other):return Vector(self.x * other.x, self.y * other.y)v1 = Vector(0, 1)
v2 = Vector(2, 3)
ic(v1 + v2)
v1 += v2
ic(v1)

ic| v1 + v2: Vertor(2,4)
ic| v1: Vertor(0,3)

我们看到,v += v2 时调用了__iadd__魔术方法。返回结果:Vertor(0,3)。但其实,我们不创建这个__iadd__魔术方法也可以。

from icecream import icclass Vector:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f'Vertor({self.x}{self.y})'def __add__(self, other):return Vector(self.x + other.x, self.y + other.y)v1 = Vector(0, 1)
v2 = Vector(2, 3)
ic(v1 + v2)
v1 += v2
ic(v1)

ic| v1 + v2: Vertor(2,4)
ic| v1: Vertor(2,4)

在本节前面提到的魔术方法中,所有使用符号触发的都有其对应的i版本。也就是:+=、-=、*=…

4.10.4.9 negpos

这2个魔术方法对应的是在数据结构之前添加一个-+符号。
neg:-obj
pos:+obj

from icecream import icclass Vector:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f'Vertor({self.x}{self.y})'def __neg__(self):return Vector(-self.x, -self.y)def __pos__(self):return Vector(self.x, self.y)v1 = Vector(-2, 3)
ic(-v1)
ic(+v1)

ic| -v1: Vertor(2,-3)
ic| +v1: Vertor(-2,3)

4.10.4.10 absinvert

abs:abs(obj)
invert:~obj # 位运算中的反转

4.10.4.11 complexintfloat

complex:complex(obj)
int:int(obj)
float:float(obj)
这3个魔术方法规定返回的结果必须是其对应的数据结构。

4.10.4.12 index

index:代表当你把这个数据结构当成index使用的时候等价于什么。
如果我们定义了这个__index__,而没有定义__ complex__、int、__float__方法的话,那么complex、int、float都会默认使用这个__index__魔法方法。

from icecream import icclass Vector:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f'Vertor({self.x}{self.y})'def __index__(self):return int(self.x)v1 = Vector(2, 3)
lst = list('Python')
ic(lst[v1])  # [v1]返回2,相当于:lst[int(self.x)]

ic| lst[v1]: ‘t’

4.10.4.13 roundtruncfloorceil

round:round(obj) # 四舍五入
trunc:math.trunc(obj) # 无条件舍弃小数
floor:math.floor(obj) # 向负无穷取整
ceil:math.ceil(obj) # 向正无穷取整


http://www.ppmy.cn/news/1026008.html

相关文章

centos-stream-9 centos9 配置国内yum源 阿里云源

源配置 tips: yum配置文件路径 /etc/yum.repos.d/centos.repo 1.备份源配置 [Very Important!]mv /etc/yum.repos.d/centos.repo /etc/yum.repos.d/centos.repo.backup2.Clean Cache: yum clean all3.Backup the Old CentOS-Base.repo If exist this file.cd /etc/yum.repos.…

题目:2535.数组元素和合数字和的绝对值

​​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;2535. 数组元素和与数字和的绝对差 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 分别计算数字和和数组元素和&#xff0c;然后求差并返回其绝对值即可。 解题代码&#xff1a; class S…

《深度学习与图像分析——基础与应用》书籍阅读

李松斌&#xff0c;刘鹏著&#xff0c;科学出版社 2023年5月20日16:32:38开始阅读&#xff0c;2023年7月12日读完。 1.基础知识 获得泛化能力是深度学习的最终目标。泛化能力是指处理未被观察个的数据的能力&#xff08;即不包含在训练数据中的数据&#xff09;。 训练集&…

HarmonyOS开发(DevEco Studio)

目录 开发环境搭建 下载DevEco Studio 进行环境配置 系统开发前端基础 应用开发目录结构 文件使用规则 基础组件介绍 Chart组件使用&#xff08;线型图案例&#xff09; 使用image-animator组件构建多图帧动画 TodoList应用构建 自定义组件使用 父子组件通信功能 路…

监控Kubernetes 控制面组件的关键指标

控制面组件的监控&#xff0c;包括 APIServer、Controller-manager&#xff08;简称 CM&#xff09;、Scheduler、etcd 四个组件。 1、APIServer APIServer 的核心职能是 Kubernetes 集群的 API 总入口&#xff0c;Kube-Proxy、Kubelet、Controller-Manager、Scheduler 等都需…

从后往前读取列表的方法

从后往前读取列表的方法 方法1&#xff1a;使用for循环遍历列表时&#xff0c;可以使用reverse()函数将列表反转&#xff0c;然后再遍历。 # 列表 num [0, 1, 2, 3]# 反向遍历 for i in reversed(num):print(i)输出结果&#xff1a; 3 2 1 0方法2&#xff1a;先计算列表长度…

并发和并行的概念

并发是指两个或多个事件在同一时间间隔内发生。操作系统的并发性是指计算机系统中同时存在多个运行的程序&#xff0c;因此它具有处理和调度多个程序同时执行的能力。在操作系统中&#xff0c;引入进程的目的是使程序能够并发执行 注意同一时间间隔&#xff08;并发&#xff0…

mybatis 中的<![CDATA[ ]]>用法及说明

<![CDATA[ ]]>作用 <![CDATA[ ]]> 在mybatis、ibatis等书写SQL的xml中比较常见&#xff0c;是一种XML语法&#xff0c;他的作用是 可以忽略xml的转义&#xff08;在该标签中的语句和字符原本是什么样的&#xff0c;在拼接成SQL后还是什么样的&#xff09; 使用&a…