34. 让类支持比较操作

有时我们希望自定义类的实例之间可以使用逻辑运算符进行比较,我们自定义比较的行为。例如,有一个矩形的类,比较两个矩形的实例时,比较的是它们的面积。

class Rectangle:
    def __init__(self, w, h):
        self.w = w
        self.h = h    
    def area(self):
        return self.w * self.h
        
rect1 = Rectangle(5,3)rect2 = Rectangle(4,4)rect1 > rect2               # => rect1.area() > rect2.area()

要求:自定义类方法实现逻辑运算符比较。

解决方案:

逻辑运算符重载,需要实现以下方法:

__lt____le____gt____ge____eq____ne__

同时,使用标准库functools下的类装饰器total_ording可以简化此过程。


  • 对于逻辑运算符重载:

数字比较

>>> a,b = 5,3>>> a < bFalse>>> a.__lt__(b)             #实际上 < 调用的是 __lt__()方法False>>> a >= bTrue>>> a.__ge__(b)             #实际上 >= 调用的是 __ge__()方法True

字符串比较

>>> s1,s2 = 'abc','abd'>>> s1 > s2False>>> s1.__gt__(s2)               #实际上 > 调用的是 __gt__()方法False>>> ord('c') > ord('d')False

对于字符串的比较,是从左到右依次比较的,通过ord()函数进行比较。

集合比较

>>> {1, 2, 3} > {4}False>>> {1, 2, 3} < {4}False>>> {1, 2, 3} == {4}False>>> {1, 2, 3} > {1, 2}True>>> {1, 2, 3} > {1, 3}True

实际上对于集合的比较,为True时,>表示前面的集合包含后面的集合,<表示后面的集合包含前面的集合,==说明两集合一样。

这就说明对于不同基本类型的逻辑运算符比较,逻辑运算符重载方法的实现是不一样的。


  • 解决方案:
from abc import ABCMeta, abstractclassmethodfrom functools import total_orderingimport math

@total_orderingclass Shape(metaclass=ABCMeta):             #抽象基类
    @abstractclassmethod    def area(self):
        pass

    def __lt__(self, obj):
        return self.area() < obj.area()

    def __eq__(self, obj):
        return self.area() == obj.area()class Rectangle(Shape):
    def __init__(self, w, h):
        self.w = w
        self.h = h    
    def area(self):
        return self.w * self.h    def __str__(self):
        return 'Rectangle: (%s, %s)' % (self.w, self.h)class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius    
    def area(self):
        return round(self.radius ** 2 * math.pi, 1)rect1 = Rectangle(5,3)rect2 = Rectangle(4,4)c = Circle(5)print(rect1 < c)print(c >= rect2)True                #结果True

首先定义抽象基类,在基类中自定义逻辑运算符重载方法,通过@total_ordering装饰器自动补全其余的重载方法,需要进行实例之间逻辑比较的类继承抽象基类即可。


上一篇:【leetcode每日刷题】49. Group Anagrams


下一篇:leetcode 438. 找到字符串中所有字母异位词(Find All Anagrams in a String)