栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Python实现让类支持比较操作

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python实现让类支持比较操作

1、如何让类支持比较操作?

        实际案例:

                有时我们希望自定义的类,实例间可以使用 ,>=,==,!= 符号进行比较,我们自定义比较的行为。例如,有一个矩形的类,我们希望比较两个矩形的实例时,比较的是他们的面积。

    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.area() > rect2.area()
    rect1 > rect2

        解决方案:

                比较符号运算符重载,需要实现以下方法:小于__lt__,小于等于__le__,大于__gt__,_大于等于_ge__,等于___eq__,不能于__ne__。

                使用标准库的funtools下的类装饰器total_ordering可以简化需要写所有运算符重载的过程。

2、代码演示

(1)实现两个实例之间的比较

from functools import total_ordering


@total_ordering
class Rectangle:
    # 定义矩形类
    def __init__(self, w, h):
        self.w = w
        self.h = h

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

    # 小于运算符的重载,other为右边对象
    def __lt__(self, obj):
        print('in __lt__')
        return self.area() < obj.area()

    def __eq__(self, obj):  # 等于
        print('in __eq__')
        return self.area() == obj.area()

    # def __le__(self, obj):  # 小于等于,装饰器会默认给创建
    #     return self < obj or self == obj
    #
    # def __gt__(self, obj):  # 大于,装饰器会默认给创建
    #     return not (self < obj or self == obj)


r1 = Rectangle(5, 3)
r2 = Rectangle(4, 4)
# 当解释器看到这样一条语句的时候,实际上调用的是r1.__lt__(r2)
# 3*5=15小于4*4=16
print(r1 < r2)
# 小于等于
print(r1 <= r2)

# 为填添加total_ordering装饰器,可以只重载定义等于和小于
# 两个方法就可以使用小于等于,运行时实际只调用了小于的行为,
# 这是因为使用装饰器后默认使用'__lt__ or __eq__ '给我们创建__le__。
print(r1 <= r2)
print(r1 > r2)
print(r1 >= r2)
print(r1 != r2)
'''
两个实例进行比较不总是同一种对象,比如再定义一个Circle类,
通过两个实例对象比较圆和矩形面积。
'''


class Circle(object):  
    # 定义一个圆
    def __init__(self, r):
        self.r = r

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


r1 = Rectangle(5, 3)
c1 = Circle(3)
# 比较矩形和圆面积,r1 <= c1是支持的,如果反过来c1 <= r1也想支持,
# 就需要在Circle类做同样比较运算符的方法重载。
print(r1 <= c1)
print('---')
print(c1 <= r1)

(2)使用抽象接口和公共基类对不同实例对象比较进行升级优化

'''
对每一种图形都写一遍比较运算符方法的重载,这样的方式很麻烦。
我们可以为图形定义一个公共抽象基类shape,并且在shape中实现这些运算符重载的函数。
在额外的定义一个抽象接口area能比较的都要实现这个area,
让所有的图形都继承这个公共基类,这种方式更好。
'''
# _*_ encoding:utf-8 _*_
from functools import total_ordering
# 导入定义抽象基类库
from abc import ABCMeta, abstractmethod


@total_ordering
class Shape(object):
    # 图形的抽象基类
    @abstractmethod  # 抽象接口装饰器
    def area(self):
        # 子类中都要实现这个接口
        pass

    # 小于运算符的重载,obj为右边对象
    def __lt__(self, obj):
        # 比较之前先做类型判断,不能让对象和数字比较
        if not isinstance(obj, Shape):
            raise TypeError('obj is not Shape')
        print('in __lt__')
        return self.area() < obj.area()

    def __eq__(self, obj):  # 等于
        if not isinstance(obj, Shape):
            raise TypeError('obj is not Shape')
        print('in __eq__')
        return self.area() == obj.area()


class Rectangle(Shape):  # 继承shape
    # 定义矩形类
    def __init__(self, w, h):
        self.w = w
        self.h = h

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


class Circle(Shape):  # 继承shape
    # 定义一个圆
    def __init__(self, r):
        self.r = r

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


'''
两个实例进行比较不总是同一种对象,比如再定义一个Circle类,
通过两个实例对象比较圆和矩形面积。
'''

r1 = Rectangle(5, 3)
c1 = Circle(3)
print(r1 <= c1)
print(r1 > c1)
# 异常验证
# print(r1 > 1)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/876152.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号