让类支持比较操作

有时我们希望自定义类,实例间可以使用<,<=,>,>=,==,!=号进行比较,我们自定义比较行为。

例如,有一个矩形类,我们希望比较两个矩形的实例时,比较的是面积。

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_ordering可以简化此过程

利用total_ordering装饰器可不必全部重载以上类似__lt__的方法,而是__lt__ & __eq__两个即可,
total_ordering会根据这两个方法推算出其他方法。
 
本例还将类抽象了出来,任何两个相比较的类都继承Shape类,Shape类提供一个抽象方法即area,
通过各种形状的面积来比较各对象的大小,在Shape类中只重载了__lt__ & __eq__,并用了装饰器total_ordering
from functools import total_ordering
from abc import ABCMeta, abstractmethod

@total_ordering
class Shape(object):
    """docstring for Shape"""
    @abstractmethod   
    def area(self):
        pass

    def __lt__(self, obj):
        if not isinstance(obj, Shape):
            raise TypeError("It's not Shape")
        return self.area() < obj.area()

    def __eq__(self, obj):
        if not isinstance(obj, Shape):
            raise TypeError("It's not Shape")
        return self.area() == obj.area()

class RectangleCompare(Shape):
    """docstring for RectangleCompare"""
    def __init__(self, w, h):
        self.w = w
        self.h = h

    def area(self):
        return self.w * self.h


class Circle(Shape):
    """docstring for Circle"""
    def __init__(self, r):
        self.r = r

    def area(self):
        return self.r ** 2 * 3.14


rc1 = RectangleCompare(2,9)
rc2 = RectangleCompare(3,4)

c1 = Circle(2)
c2 = Circle(3)

print rc1>=rc2
print c1.r,' ',c1.area()
print rc1.area(),' ',c2.area()
print rc1>c2
print rc2==1

运行结果:
TrueTraceback (most recent call last):
  File "D:\python space\classCompare.py", line 49, in <module>
True
2   12.56
18   28.26
False
    print rc2==1
  File "D:\python space\classCompare.py", line 18, in __eq__
    raise TypeError("It's not Shape")
TypeError: It's not Shape

 

posted @ 2020-09-22 19:44  Edward_han  阅读(130)  评论(0编辑  收藏  举报