程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python實現讓類支持比較操作

編輯: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)


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved