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)
上一篇下一篇

猜你喜欢

热点阅读