functools.total_ordering
2020-05-08 本文已影响0人
RayRaymond
定义类的比较方式,实现各种比较运算的算子类,既可用于numbers.Number的子类,也可用于半数值型类。
内部逻辑大概是如果是实现了__lt__()
,那么程序会自动帮你实现了__gt__()
, __ge__()
等等的N多函数。
def total_ordering(cls):
"""Class decorator that fills in missing ordering methods"""
convert = {
'__lt__': [('__gt__', lambda self, other: not (self < other or self == other)),
('__le__', lambda self, other: self < other or self == other),
('__ge__', lambda self, other: not self < other)],
'__le__': [('__ge__', lambda self, other: not self <= other or self == other),
('__lt__', lambda self, other: self <= other and not self == other),
('__gt__', lambda self, other: not self <= other)],
'__gt__': [('__lt__', lambda self, other: not (self > other or self == other)),
('__ge__', lambda self, other: self > other or self == other),
('__le__', lambda self, other: not self > other)],
'__ge__': [('__le__', lambda self, other: (not self >= other) or self == other),
('__gt__', lambda self, other: self >= other and not self == other),
('__lt__', lambda self, other: not self >= other)]
}
roots = set(dir(cls)) & set(convert)
if not roots:
raise ValueError('must define at least one ordering operation: < > <= >=')
root = max(roots) # prefer __lt__ to __le__ to __gt__ to __ge__
for opname, opfunc in convert[root]:
if opname not in roots:
opfunc.__name__ = opname
opfunc.__doc__ = getattr(int, opname).__doc__
setattr(cls, opname, opfunc)
return cls
示例
from functools import total_ordering
@total_ordering
class Door(object):
def __init__(self):
self.value = 0
self.first_name = ''
self.last_name = ''
def __eq__(self, other):
print('=== my eq===')
return (self.first_name, self.last_name) == (other.first_name, other.last_name)
def __gt__(self, other):
print('=== my total_ordering===')
return (self.first_name, self.last_name) > (other.first_name, other.last_name)
a = Door()
b = Door()
a.first_name = 'ouyang'
a.last_name = 'guoge'
b.first_name = 'aaaa'
b.last_name = 'bbbb'
print (a == b)
print (a > b)
print (a < b)
print (a <= b)
print (a >= b)