8.24 让类支持比较操作
问题
你想让某个类的实例支持标准的比较运算(比如>=,!=,<=,<等),但是又不想去实现那一大丢的特殊方法。
解决方案
装饰器 functools.total_ordering
就是用来简化这个处理的。 使用它来装饰一个来,你只需定义一个 __eq__()
方法, 外加其他方法(__lt__
, __le__
, __gt__
, or __ge__
)中的一个即可。 然后装饰器会自动为你填充其它比较方法。
from functools import total_ordering
class Room:
def __init__(self, name, length, width):
self.name = name
self.length = length
self.width = width
self.square_feet = self.length * self.width
@total_ordering
class House:
def __init__(self, name, style):
self.name = name
self.style = style
self.rooms = list()
@property
def living_space_footage(self):
return sum(r.square_feet for r in self.rooms)
def add_room(self, room):
self.rooms.append(room)
def __str__(self):
return '{}: {} square foot {}'.format(self.name,
self.living_space_footage,
self.style)
def __eq__(self, other):
return self.living_space_footage == other.living_space_footage
def __lt__(self, other):
return self.living_space_footage < other.living_space_footage
这里我们只是给House类定义了两个方法:__eq__()
和 __lt__()
,它就能支持所有的比较操作:
print('Is h1 bigger than h2?', h1 > h2) # prints True
print('Is h2 smaller than h3?', h2 < h3) # prints True
讨论
其实 total_ordering
装饰器也没那么神秘。 它就是定义了一个从每个比较支持方法到所有需要定义的其他方法的一个映射而已。 比如你定义了 __le__()
方法,那么它就被用来构建所有其他的需要定义的那些特殊方法。 实际上就是在类里面像下面这样定义了一些特殊方法:
class House:
def __eq__(self, other):
pass
def __lt__(self, other):
pass
# Methods created by @total_ordering
__le__ = lambda self, other: self < other or self == other
__gt__ = lambda self, other: not (self < other or self == other)
__ge__ = lambda self, other: not (self < other)
__ne__ = lambda self, other: not self == other
Last updated
Was this helpful?