Actual case :
Sometimes we want custom classes , Between instances, you can use ,>=,==,!= Compare symbols , We customize the behavior of comparison . for example , There is a rectangular class , When we want to compare instances of two rectangles , Compare their area .
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
Solution :
Comparison symbol operator overloading , The following methods need to be implemented : Less than __lt__, Less than or equal to __le__, Greater than __gt__,_ Greater than or equal to _ge__, be equal to ___eq__, Cannot be on __ne__.
Using the standard library funtools Class decorator under total_ordering It can simplify the process of writing all operator overloads .
(1) Realize the comparison between two instances
from functools import total_ordering
@total_ordering
class Rectangle:
# Define rectangle class
def __init__(self, w, h):
self.w = w
self.h = h
def area(self):
return self.w * self.h
# Overload of less than operator ,other For the right object
def __lt__(self, obj):
print('in __lt__')
return self.area() < obj.area()
def __eq__(self, obj): # be equal to
print('in __eq__')
return self.area() == obj.area()
# def __le__(self, obj): # Less than or equal to , The decorator will be created by default
# return self < obj or self == obj
#
# def __gt__(self, obj): # Greater than , The decorator will be created by default
# return not (self < obj or self == obj)
r1 = Rectangle(5, 3)
r2 = Rectangle(4, 4)
# When the interpreter sees such a statement , It's actually calling theta r1.__lt__(r2)
# 3*5=15 Less than 4*4=16
print(r1 < r2)
# Less than or equal to
print(r1 <= r2)
# Add... For filling total_ordering Decorator , You can overload definitions that are equal to and less than
# Two methods can use less than or equal to , The runtime actually invokes only behaviors less than ,
# This is because the decorator is used by default '__lt__ or __eq__ ' Create... For us __le__.
print(r1 <= r2)
print(r1 > r2)
print(r1 >= r2)
print(r1 != r2)
'''
Comparing two instances is not always the same object , For example, define another Circle class ,
Compare the area of circle and rectangle through two instance objects .
'''
class Circle(object):
# Define a circle
def __init__(self, r):
self.r = r
def area(self):
return self.r ** 2 * 3.14
r1 = Rectangle(5, 3)
c1 = Circle(3)
# Compare rectangular and circular areas ,r1 <= c1 Is to support the , If I go the other way c1 <= r1 Also want to support ,
# It needs to be in Circle Class to do the same comparison operator method overloading .
print(r1 <= c1)
print('---')
print(c1 <= r1)
(2) Use abstract interfaces and public base classes to upgrade and optimize the comparison of different instance objects
'''
Write an overload of the comparison operator method for each graph , This way is very troublesome .
We can define a common abstract base class for graphics shape, And in shape Functions that implement these operator overloads in .
In addition, define an abstract interface area All that can be compared should achieve this area,
Let all graphics inherit this common base class , This way is better .
'''
# _*_ encoding:utf-8 _*_
from functools import total_ordering
# Import definition abstract base class library
from abc import ABCMeta, abstractmethod
@total_ordering
class Shape(object):
# Abstract base class of graphics
@abstractmethod # Abstract interface decorator
def area(self):
# Subclasses must implement this interface
pass
# Overload of less than operator ,obj For the right object
def __lt__(self, obj):
# Make type judgment before comparison , You can't compare objects with numbers
if not isinstance(obj, Shape):
raise TypeError('obj is not Shape')
print('in __lt__')
return self.area() < obj.area()
def __eq__(self, obj): # be equal to
if not isinstance(obj, Shape):
raise TypeError('obj is not Shape')
print('in __eq__')
return self.area() == obj.area()
class Rectangle(Shape): # Inherit shape
# Define rectangle class
def __init__(self, w, h):
self.w = w
self.h = h
def area(self):
return self.w * self.h
class Circle(Shape): # Inherit shape
# Define a circle
def __init__(self, r):
self.r = r
def area(self):
return self.r ** 2 * 3.14
'''
Comparing two instances is not always the same object , For example, define another Circle class ,
Compare the area of circle and rectangle through two instance objects .
'''
r1 = Rectangle(5, 3)
c1 = Circle(3)
print(r1 <= c1)
print(r1 > c1)
# Exception verification
# print(r1 > 1)