Python 正确重写运算符(重载)

本文介绍了Python中运算符重载的概念和重要性,讨论了Python对运算符重载的限制。详细阐述了一元运算符如-、+、~及abs()的重载,并通过示例说明了如何在Vector类中实现这些运算。接着探讨了中缀运算符如加法+的重载,包括如何处理不同类型的运算对象,以及乘法*的重载,尤其是矩阵乘法@的实现。文章还涵盖了比较运算符的重载,以及增量赋值运算符如+=的用法。总结了运算符重载的规则和注意事项,强调了返回新对象的重要性,并给出了不同类型的兼容处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

运算符重载的作用是让用户定义的对象使用中缀运算符(如+和|)和一元运算符(如-和~)。

在Python中,这些也算是运算符:

函数调用:()

属性访问:.

元素访问和切片:[]

运算符重载基础

在某些圈子中,运算符重载的名声不好,比如Java之父说过:我决定不支持运算符重载,这完全是个人选择,因为我见过太多C++程序员滥用它。

但是如果使用得当,API会变得更好用,代码变的I易于阅读。

Python施加了一些限制,做好了灵活性、可用性和安全性方面的平衡:

  • 不能重载内置类型的运算符

  • 不能新建运算符,只能重载现有的

  • 某些运算符不能重载:is、and、or、not (但是位运算符&、|、~可以)

下面依次介绍:一元运算符、中缀运算符、比较运算符、增量赋值运算符。

一元运算符

  • - (__neg__) 一元取负运算符。如果x是-2,那么-x == 2

  • + (__pos__)一元取正运算符。通常x == +x,也有一些例外

  • ~ (__invert__)对整数按位取反。定义为~x == -(x+1) ,如果x是2,那么~x ==-3

  • abs (__abs__) 取绝对值

要实现一元运算符,就实现括号中对应的特殊方法,这些特殊方法都只有一个参数self。要遵守一个原则:始终返回一个新的对象,也就是说不能修改self,要创建并返回合适类型的新实例。对于+和-来说,返回的结果可能是和self同一类型的实例;对于abs来说结果应该是一个标量;但是对于~来说,很难说返回什么是合理的,因为可能不是处理整数的位,例如在ORM中,SQL where子句应该返回反集。

示例,Vector类中实现了__abs__方法,补充上__neg__和__pos__方法

    def __abs__(self):
        """绝对值 (向量取模)"""
        return math.sqrt(sum(x * x for x in self.__components))  # math.sqrt()求平方根。先用sum求每个分量的平方之和,然后开平方
    
    def __neg__(self):
        """取负值,构建新的实例,每个分量都取反"""
        return Vector(-x for x in self)
    
    def __pos__(self):
        """取正值,构建新的实例,传入self各个分量"""
        return Vector(self)

补充下在什么时候x和+x不相等:

在Python中几乎所有情况下x == +x,但是在标准库中也有例外的情况,有两例

第一例是decimal.Decimal有关,这是因为使用+时,精度变了

import decimal

ctx = decimal.getcontext()  # 获取当前全局算术运算的上下文引用
ctx.prec = 40  # 把算术运算上下文精度设为40

one_third = decimal.Decimal('1') / decimal.Decimal('3')
print(one_third)
print(+one_third)
print(one_third == +one_third)  # 比较

ctx.prec = 28  # 把算术运算上下文精度设为28

print(one_third)
print(+one_third)
print(one_third == +one_third)  # 比较
打印
0.3333333333333333333333333333333333333333
0.3333333333333333333333333333333333333333
True
0.3333333333333333333333333333333333333333
0.3333333333333333333333333333
False

上面可以看到,在改变上下文精度后,再次与+one_third比较时就不相等了,因为+运算符会返回一个新的实例对象,而这个实例对象是根据当时的上下文精度创建的。

第二例是collection.Counter有关,Counter类实现了几个算术运算符,例如中缀运算符+的作用是把两个Counter计数器加到一起,两边相加时,负值和零值可能会改变。

而对于一元运算符+等同于加上一个空的Counter,因此他产生一个新的Counter且仅保留大于零的计数器。

import collections
ct = 
### 如何在Python重载运算符 #### 运算符重载的概念 在面向对象编程中,运算符重载允许程序员定义类的行为来响应特定的操作符。这使得可以使用标准操作符(如`+`, `-`, `*`等)处理自定义类型的对象。 #### 实现加法运算符的例子 对于两个数值相加非常直观;但对于复杂的数据结构比如矩阵或字符串,则需要指定其行为。下面是一个简单的例子展示如何通过实现特殊方法`__add__()`来自定义类中的加法规则: ```python class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __add__(self, other): """Overloading the '+' operator""" x = self.x + other.x y = self.y + other.y return Point(x, y) p1 = Point(2, 3) p2 = Point(-1, 2) result = p1 + p2 # Calls p1.__add__(p2) print(f"Result of addition: ({result.x}, {result.y})") ``` 这段代码创建了一个名为Point的新数据类型,并实现了当两点相加时应该如何计算的结果[^1]。 #### 绝对值函数的应用场景 除了基本的数学运算外,在某些情况下可能还需要支持其他内置功能。例如,为了能够调用`abs()`获得实例大小的信息,可以在类内部定义`__abs__()`方法: ```python from math import sqrt class Vector: def __init__(self, x_comp, y_comp): self.x_comp = x_comp self.y_comp = y_comp def __abs__(self): magnitude = sqrt(self.x_comp**2 + self.y_comp**2) return magnitude v = Vector(3, 4) magnitude_of_v = abs(v) # Returns 5.0 as per Pythagorean theorem. print(magnitude_of_v) ``` 此部分展示了如何利用绝对值特性为Vector类提供几何意义下的模长属性访问方式[^4]。 #### 关系比较运算符的支持 如果希望自己的类能够在条件判断语句里被用来做真假测试或者与其他同类变量相互对比的话,那么就需要考虑加入相应的魔术方法了。这里给出一个关于关系运算符的小案例: ```python class Temperature: def __init__(self, celsius_temperature): self.celsius_temperature = celsius_temperature def __lt__(self, other): return self.celsius_temperature < other.celsius_temperature t1 = Temperature(25) t2 = Temperature(30) if t1 < t2: print('It\'s cooler today.') else: print('The weather got warmer.') ``` 上述片段说明了怎样让Temperature类的对象之间能正常执行小于号(<>)这样的二元关系判定逻辑[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值