流畅的Python(十三)-正确重载运算符

一、核心要义

1. 一元运算符重载

2.加法和乘法运算符重载

3.比较运算符重载

4.增量赋值运算符重载

二、代码示例

1、一元运算符重载

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/25 10:35
# @Author  : Maple
# @File    : 01-一元运算符.py
# @Software: PyCharm"""
为第10章的Vector类重载运算符 +(__pos__,实现效果: x = +x) 和 - (__neg__,实现效果 x = -x)"""
import functools
import math
import operator
import reprlib
from array import arrayclass Vector:typecode = 'd'shortcut_names = 'xyzt'def __init__(self, components):self._components = array(self.typecode, components)def __repr__(self):# 返回的components是str类型components = reprlib.repr(self._components)components = components[components.find('['):-1]return 'Vector({})'.format(components)def __str__(self):return str(tuple(self))def __iter__(self):return iter(self._components)def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(self._components))def __bool__(self):return bool(abs(self))def __abs__(self):return math.sqrt(sum(x * x for x in self._components))@classmethoddef frombytes(cls, octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(memv)def __len__(self):return len(self._components)def __getitem__(self, index):cls = type(self)if isinstance(index, slice):return cls(self._components[index])elif isinstance(index, numbers.Integral):return self._components[index]else:msg = '{cls.__name__} indices must be integers'return TypeError(msg.format(cls=cls))def __getattr__(self, item):# 只有当v.x实例不存在x属性时,才会调用getattrcls = type(self)if len(item) == 1:position = cls.shortcut_names.find(item)if 0 <= position < len(self._components):return self._components[position]msg = '{.__name__!r} object has not attribute {!r}'raise AttributeError(msg.format(cls, item))def __setattr__(self, name, value):cls = type(self)if len(name) == 1:# 限制修改'xyzt'单字母属性值if name in cls.shortcut_names:error = 'readonly attribute {attr_name!r}'elif name.islower():# 限制修改单字母(a-z)的属性值error = "can't set attributes 'a' to 'z' in {cls_name}!r"else:error = ''if error:msg = error.format(cls_name=cls, attr_name=name)raise AttributeError(msg)# 允许修改名字为其它值的属性super().__setattr__(name, value)def __eq__(self, other):# 如果分量太多,下面这种方式效率太低# return tuple(self) == tuple(other)if len(self) != len(other):return Falsefor x, y in zip(self, other):if x != y:return Falsereturn Truedef __hash__(self):# 生成一个迭代器hashes = (hash(x) for x in self._components)return functools.reduce(operator.xor, hashes, 0)# 等价于下面的写法# return functools.reduce(lambda x,y : x *y ,hashes,0)# - 运算符重载def __neg__(self):return Vector(-x for x in self)# + 运算符重载def __pos__(self):return  Vector(x for x in self)if __name__ == '__main__':# 1. - 运算符重载测试v = Vector([1,2,3,4])print(-v) # (-1.0, -2.0, -3.0, -4.0)# 2. + 运算符重载测试print(v == +v ) # True

2、向量加法运算符重载

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/25 10:44
# @Author  : Maple
# @File    : 02-重载向量加法运算符.py
# @Software: PyCharm"""
1.对于序列类型,默认的加法运算行为是,比如 [1,2,3] + [1,1,1] = [1,2,3,1,1,1]
2.但实际我们预期的结果是 [1,2,3] + [1,1,1] = [2,3,4]
"""#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/25 10:35
# @Author  : Maple
# @File    : 01-一元运算符.py
# @Software: PyCharm
import itertools"""
为第10章的Vector类重载运算符 +(__pos__,实现效果: x = +x) 和 - (__neg__,实现效果 x = -x)"""
import functools
import math
import operator
import reprlib
from array import arrayclass Vector:typecode = 'd'shortcut_names = 'xyzt'def __init__(self, components):self._components = array(self.typecode, components)def __repr__(self):# 返回的components是str类型components = reprlib.repr(self._components)components = components[components.find('['):-1]return 'Vector({})'.format(components)def __str__(self):return str(tuple(self))def __iter__(self):return iter(self._components)def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(self._components))def __bool__(self):return bool(abs(self))def __abs__(self):return math.sqrt(sum(x * x for x in self._components))@classmethoddef frombytes(cls, octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(memv)def __len__(self):return len(self._components)def __getitem__(self, index):cls = type(self)if isinstance(index, slice):return cls(self._components[index])elif isinstance(index, numbers.Integral):return self._components[index]else:msg = '{cls.__name__} indices must be integers'return TypeError(msg.format(cls=cls))def __getattr__(self, item):# 只有当v.x实例不存在x属性时,才会调用getattrcls = type(self)if len(item) == 1:position = cls.shortcut_names.find(item)if 0 <= position < len(self._components):return self._components[position]msg = '{.__name__!r} object has not attribute {!r}'raise AttributeError(msg.format(cls, item))def __setattr__(self, name, value):cls = type(self)if len(name) == 1:# 限制修改'xyzt'单字母属性值if name in cls.shortcut_names:error = 'readonly attribute {attr_name!r}'elif name.islower():# 限制修改单字母(a-z)的属性值error = "can't set attributes 'a' to 'z' in {cls_name}!r"else:error = ''if error:msg = error.format(cls_name=cls, attr_name=name)raise AttributeError(msg)# 允许修改名字为其它值的属性super().__setattr__(name, value)def __eq__(self, other):# 如果分量太多,下面这种方式效率太低# return tuple(self) == tuple(other)if len(self) != len(other):return Falsefor x, y in zip(self, other):if x != y:return Falsereturn Truedef __hash__(self):# 生成一个迭代器hashes = (hash(x) for x in self._components)return functools.reduce(operator.xor, hashes, 0)# 等价于下面的写法# return functools.reduce(lambda x,y : x *y ,hashes,0)# - 运算符重载def __neg__(self):return Vector(-x for x in self)# + 运算符重载def __pos__(self):return  Vector(x for x in self)def __add__(self,other):# 返回两个对象的配对元组迭代器try:pairs = itertools.zip_longest(self,other,fillvalue=0.0)return Vector(a + b for a,b in pairs)except TypeError:raise NotImplementeddef __radd__(self, other):# 调用方式other.__add__(self)# 注意不要漏returnreturn self + otherif __name__ == '__main__':# 1. - 运算符重载测试v = Vector([1,2,3,4])print(-v) # (-1.0, -2.0, -3.0, -4.0)# 2. + 运算符重载测试print(v == +v ) # True# 3. 加法运算重载测试"""基本流程1. Vector对象 + 另外一个可迭代对象,正常返回结果2. 非Vector类型的可迭代对象  +  Vector对象,首先会调用add, 因为add方法要求第一个对象是Vector类型,所以会报错:can only concatenate tuple (not "Vector") to tuple抛出NotImplemented错误3. 程序会继续调用__radd__方法,之后就会调用Vector对象.__add__(other),然后正常返回结果"""print(v + (1,2,3,4)) #(2.0, 4.0, 6.0, 8.0)print((1,2,3,4) + v) #(2.0, 4.0, 6.0, 8.0)

3、向量乘法运算符重载

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/25 11:05
# @Author  : Maple
# @File    : 03-重载标量乘法运算符.py
# @Software: PyCharm
import functools
import itertools
import numbers
from _ast import operator
from array import arrayclass Vector:typecode = 'd'shortcut_names = 'xyzt'def __init__(self, components):self._components = array(self.typecode, components)def __repr__(self):# 返回的components是str类型components = reprlib.repr(self._components)components = components[components.find('['):-1]return 'Vector({})'.format(components)def __str__(self):return str(tuple(self))def __iter__(self):return iter(self._components)def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(self._components))def __bool__(self):return bool(abs(self))def __abs__(self):return math.sqrt(sum(x * x for x in self._components))@classmethoddef frombytes(cls, octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(memv)def __len__(self):return len(self._components)def __getitem__(self, index):cls = type(self)if isinstance(index, slice):return cls(self._components[index])elif isinstance(index, numbers.Integral):return self._components[index]else:msg = '{cls.__name__} indices must be integers'return TypeError(msg.format(cls=cls))def __getattr__(self, item):# 只有当v.x实例不存在x属性时,才会调用getattrcls = type(self)if len(item) == 1:position = cls.shortcut_names.find(item)if 0 <= position < len(self._components):return self._components[position]msg = '{.__name__!r} object has not attribute {!r}'raise AttributeError(msg.format(cls, item))def __setattr__(self, name, value):cls = type(self)if len(name) == 1:# 限制修改'xyzt'单字母属性值if name in cls.shortcut_names:error = 'readonly attribute {attr_name!r}'elif name.islower():# 限制修改单字母(a-z)的属性值error = "can't set attributes 'a' to 'z' in {cls_name}!r"else:error = ''if error:msg = error.format(cls_name=cls, attr_name=name)raise AttributeError(msg)# 允许修改名字为其它值的属性super().__setattr__(name, value)def __eq__(self, other):# 如果分量太多,下面这种方式效率太低# return tuple(self) == tuple(other)if len(self) != len(other):return Falsefor x, y in zip(self, other):if x != y:return Falsereturn Truedef __hash__(self):# 生成一个迭代器hashes = (hash(x) for x in self._components)return functools.reduce(operator.xor, hashes, 0)# 等价于下面的写法# return functools.reduce(lambda x,y : x *y ,hashes,0)# - 运算符重载def __neg__(self):return Vector(-x for x in self)# + 运算符重载def __pos__(self):return  Vector(x for x in self)def __add__(self,other):# 返回两个对象的配对元组迭代器try:pairs = itertools.zip_longest(self,other,fillvalue=0.0)return Vector(a + b for a,b in pairs)except TypeError:raise NotImplementeddef __radd__(self, other):# 调用方式other.__add__(self)# 注意不要漏returnreturn self + otherdef __mul__(self, scalar):# scalar参数的值要是数字if isinstance(scalar,numbers.Real):return Vector(n * scalar for n in self)else:return NotImplementeddef __rmul__(self, scalar):return self * scalarif __name__ == '__main__':# 乘法运算符测试v = Vector([1,2,3])print(v * 2) # # (2.0, 4.0, 6print(v * True) # (1.0, 2.0, 3.0)from fractions import  Fractionprint(v * Fraction(1,3)) # (0.3333333333333333, 0.6666666666666666, 1.0)

4、比较运算符重载

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/25 12:48
# @Author  : Maple
# @File    : 04-比较运算符.py
# @Software: PyCharmimport functools
import itertools
import math
import numbers
from _ast import operator
from array import arrayclass Vector:typecode = 'd'shortcut_names = 'xyzt'def __init__(self, components):self._components = array(self.typecode, components)def __repr__(self):# 返回的components是str类型components = reprlib.repr(self._components)components = components[components.find('['):-1]return 'Vector({})'.format(components)def __str__(self):return str(tuple(self))def __iter__(self):return iter(self._components)def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(self._components))def __bool__(self):return bool(abs(self))def __abs__(self):return math.sqrt(sum(x * x for x in self._components))@classmethoddef frombytes(cls, octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(memv)def __len__(self):return len(self._components)def __getitem__(self, index):cls = type(self)if isinstance(index, slice):return cls(self._components[index])elif isinstance(index, numbers.Integral):return self._components[index]else:msg = '{cls.__name__} indices must be integers'return TypeError(msg.format(cls=cls))def __getattr__(self, item):# 只有当v.x实例不存在x属性时,才会调用getattrcls = type(self)if len(item) == 1:position = cls.shortcut_names.find(item)if 0 <= position < len(self._components):return self._components[position]msg = '{.__name__!r} object has not attribute {!r}'raise AttributeError(msg.format(cls, item))def __setattr__(self, name, value):cls = type(self)if len(name) == 1:# 限制修改'xyzt'单字母属性值if name in cls.shortcut_names:error = 'readonly attribute {attr_name!r}'elif name.islower():# 限制修改单字母(a-z)的属性值error = "can't set attributes 'a' to 'z' in {cls_name}!r"else:error = ''if error:msg = error.format(cls_name=cls, attr_name=name)raise AttributeError(msg)# 允许修改名字为其它值的属性super().__setattr__(name, value)def __eq__(self, other):# 下面这种写法存在一个问题,比如Vector([1,2,3]) 和(1,2,3)会被判断成相等,但大部分情况下,我们应该是预期不相等的结果# return tuple(self) == tuple(other)# 改写:另外一个对象必须是Vector对象,才可能相等if isinstance(other,Vector):return (len(self) == len(other) and all( x == y for x in self for y in other))else:return NotImplementeddef __hash__(self):# 生成一个迭代器hashes = (hash(x) for x in self._components)return functools.reduce(operator.xor, hashes, 0)# 等价于下面的写法# return functools.reduce(lambda x,y : x *y ,hashes,0)# - 运算符重载def __neg__(self):return Vector(-x for x in self)# + 运算符重载def __pos__(self):return  Vector(x for x in self)def __add__(self,other):# 返回两个对象的配对元组迭代器try:pairs = itertools.zip_longest(self,other,fillvalue=0.0)return Vector(a + b for a,b in pairs)except TypeError:raise NotImplementeddef __radd__(self, other):# 调用方式other.__add__(self)# 注意不要漏returnreturn self + otherdef __mul__(self, scalar):# scalar参数的值要是数字if isinstance(scalar,numbers.Real):return Vector(n * scalar for n in self)else:return NotImplementeddef __rmul__(self, scalar):return self * scalarif __name__ == '__main__':v = Vector([1,2,3])print(v == (1,2,3)) # False

5、增量赋值运算符重载

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/25 12:54
# @Author  : Maple
# @File    : 05-增量赋值运算符.py
# @Software: PyCharm
import abcclass Tombola(abc.ABC):@abc.abstractmethoddef load(self,iterable):"""从可迭代对象中加载元素"""@abc.abstractmethoddef pick(self):"""随机删除元素,然后将其返回如果实例为空,这个方法应该抛出LookupError"""def loaded(self):"""如果至少有一个元素,则返回True,否则返回False"""return bool(self.inspect())def inspect(self):"""返回一个有序元组,由当前元素构成"""items = []while True:try:items.append(self.pick())except LookupError:breakself.load(items)return tuple(sorted(items))class AddableBingoCage(Tombola):def __init__(self,items):self._items = list(items)def pick(self):return  self._items.pop()def __add__(self,other):# 另外一个对象必须是Tombola类型,才可以使用 + 运算符if isinstance(other,Tombola):return AddableBingoCage(self.inspect() + other.inspect())else:return NotImplementeddef __iadd__(self, other):if isinstance(other,Tombola):other_iterable = other.inspect()else:try:other_iterable = iter(other)except TypeError:cls_name = type(self).__name__msg = "right operand in += must be {!r} or an iterable"raise TypeError(msg.format(cls_name))self.load(other_iterable)# iadd是就地改变对象,所以要返回改变之后的对象本身return selfdef load(self,iterable):for i in iterable:self._items.append(i)def __iter__(self):return (x for x in self._items)# def __str__(self):#     return str(tuple(self))def __repr__(self):return 'Vector{}'.format(tuple(self))def inspect(self):return self._itemsif __name__ == '__main__':# 1.就地修改(iadd)测试ab = AddableBingoCage([1,2,3])ab += [4,5]print(ab) # Vector(1, 2, 3, 4, 5)# ab += 1 #TypeError: right operand in += must be 'AddableBingoCage' or an iterable# 2.相加(add)测试#ab_new = ab + [1,2] # TypeError: unsupported operand type(s) for +: 'AddableBingoCage' and 'list'ab2 = AddableBingoCage([10,11])ab_new = ab + ab2print(ab_new) # Vector(1, 2, 3, 4, 5, 10, 11)

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

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

相关文章

python运行报错CryptographyDeprecationWarning,Upgrade pyOpenSSL now.

【问题描述】 运行一段含有AES加解密的代码&#xff0c;总是有warning提示出现&#xff0c;如下&#xff1a; D:\Python38\lib\site-packages\cryptography\hazmat\backends\openssl\x509.py:14: CryptographyDeprecationWarning: This version of cryptography contains a t…

NXP实战笔记(九):S32K3xx基于RTD-SDK在S32DS上配置 CRCIRQPower

目录 1、CRC概述 1.1、CRC配置 1.2、代码示例 2、INTCTRL 3、Power 1、CRC概述 硬件CRC产生16或者32bit的&#xff0c;S32K3提供了可编程多项式与其他参数需求。 CRC图示如下 1.1、CRC配置 暂时DMA不怎么会用&#xff0c;所以没有启用DMA CRC的选择 这点需要十分注意&…

完美解决ubuntu+windows双系统下时间不正确问题

在同一台电脑上安装ubuntuwindows双系统时&#xff0c;会出现某个系统的时间不正确的问题&#xff0c;而由于windows同步时间实在是太慢了&#xff0c;如果不去解决&#xff0c;windows上的时间大概率一直都是不对的。 原因分析 windows采用LocalTime机制设置时间&#xff0c…

【力扣白嫖日记】178.分数排名

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 178.分数排名 表&#xff1a;Scores 列名类型idintscoredecimal 在 SQL 中&#xff0c;id 是该表的主键。 …

stm32利用CubeMX实现外部中断触发数码管加减数

首先打开proteus绘制电路图&#xff0c;如下&#xff1a; 然后打开CubeMX&#xff0c;配置晶振和GPIO&#xff1a; 接下来就是生成keil工程文件&#xff0c;用keil打开。 新建一个desplay.h文件&#xff1a;下面是全部代码 #ifndef __DESPLAY_H #define __DESPLAY_H #endif#i…

索引大战:探秘InnoDB数据库中B树和Hash索引的优劣

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 索引大战&#xff1a;探秘InnoDB数据库中B树和Hash索引的优劣 前言B树索引的深度解析Hash索引的奥秘揭晓性能对比分析 前言 在当今软件开发的世界中&#xff0c;数据库扮演着至关重要的角色。而InnoD…

QYWX企业微信的公告信息限制保存pdf的破解

公司使用企业微信好几年&#xff0c;重大的消息使用公告信息这个模块。可重要的消息无法保存&#xff0c;只能在线收藏。这个玩意只考虑到了维护企业利益&#xff0c;无视员工利益。 后来发现可以利用windows的虚拟打印机&#xff0c;将公告打印成pdf。 用了一段时间&#xf…

[算法沉淀记录] 排序算法 —— 冒泡排序

排序算法 —— 冒泡排序 基本概念 冒泡排序是一种简单的排序算法。它重复地遍历要排序的列表&#xff0c;一次比较两个元素&#xff0c;并交换它们的位置&#xff0c;如果它们不是按照升序排列的。这步遍历是重复进行的&#xff0c;直到没有再需要交换&#xff0c;也就是说该…

xtu oj 1353 Digit String

题目描述 小明获得了一些密码的片段&#xff0c;包含0∼9,A∼F 这些字符&#xff0c;他猜这些是某个进制下的一个整数的数码串。 小明想知道从2到16进制中&#xff0c;哪些进制下&#xff0c;这个数码串的对应的十进制整数值&#xff0c;等于n? 输入 存在不超过1000个样例&…

注入工具SQLMAP教程:Tamper编写;指纹修改;高权限操作;目录架构等

注入工具SQLMAP教程&#xff1a;Tamper编写;指纹修改;高权限操作;目录架构 #知识点&#xff1a; 1、SQLMAP-常规猜解&字典配置 2、SQLMAP-权限操作&文件命令 3、SQLMAP-Tamper&使用&开发 4、SQLMAP-调试指纹&风险等级 #参考文章&#xff1a; https://w…

代码随想录刷题第41天

首先是01背包的基础理论&#xff0c;背包问题&#xff0c;即如何在有限数量的货物中选取使具有一定容量的背包中所装货物价值最大。使用动规五步曲进行分析&#xff0c;使用二维数组do[i][j]表示下标从0到i货物装在容量为j背包中的最大价值&#xff0c;dp[i][j]可由不放物品i&a…

wpf 数据绑定 数据转换

1.概要 数据绑定&#xff0c;有时候绑定的数据源和目标的数据类型不同&#xff0c;这时候就需要转换。 2.代码 2.1 xaml(eXtensible Application Markup Language) 可扩展应用程序标记语言 <Window x:Class"WpfApp6.MainWindow"xmlns"http://schemas.mi…

【设计模式】策略模式及函数式编程的替代

本文介绍策略模式以及使用函数式编程替代简单的策略模式。 策略模式 在策略模式&#xff08;Strategy Pattern&#xff09;中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。 在策略模式定义了一系列算法或策略&#xff0c;并将每个算法封装在独立…

《论文阅读》利用提取的情感原因提高共情对话生成的内容相关性 CCL 2022

《论文阅读》利用提取的情感原因提高共情对话生成的内容相关性 前言简介模型架构情绪识别情绪原因提取实验结果示例总结前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《Using Extracted Emotion Caus…

c语言常见操作符及操作符优先级

目录 概述1. 算术操作符&#xff1a;2. 关系操作符&#xff1a;3. 逻辑操作符&#xff1a;4. 位操作符&#xff1a; *常见操作符优先级* 概述 C语言中有多种操作符&#xff0c;用于执行不同的操作。下面是一些常见的C语言操作符以及示例代码&#xff1a; 1. 算术操作符&…

Day04 嵌入式---基本定时器

定时器概述 1、软件定时原理 使⽤纯软件的⽅式实现定时功能。 存在的问题&#xff1a;定时不太精准。CPU死等。 1&#xff09;压栈出栈需要花费时间 2&#xff09;ARM流⽔线体系架构的原因 2、定时器定时原理 使用精准的时基&#xff0c;通过硬件方式&#xff0c;实现定…

区块链笔记(三)

超级账本 如果说比特币为代表的加密货币提供了区块链技术应用的原型&#xff0c;以太坊为代表的智能合约平台延伸了区块链技术的适用场景&#xff0c;那么面向企业场景的超级账本项目则开拓了区块链技术的全新阶段。超级账本首次将区块链技术引入到了联盟账本的应用场景&#…

上传到服务器的图片资源如何读取

说两种方式&#xff0c;直接上代码&#xff1a; 1.前提图片已经存储在服务器上&#xff0c;携带图片地址过去通过输入输出流进行图片下载查看 前端&#xff1a; <img v-else :src"/chat/download?namemessage.url"/>后端&#xff1a; GetMapping("/dow…

3d Slicer软件一种新的体绘制方式

vtk Multi-Volumne试验性体绘制方式&#xff0c;细节更丰富&#xff0c;影像更清晰&#xff0c;值得学习使用

利用Spring Boot实现MQTT在物联网中的应用

在物联网&#xff08;IoT&#xff09;领域&#xff0c;消息队列遵循发布/订阅模型的MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;协议变得越来越受欢迎。本文将深入探讨如何在Spring Boot中使用MQTT&#xff0c;并讨论其与其他中间件的集成以及在物联网中…