8.24 让类支�比较�作¶
问题¶
ä½ æƒ³è®©æŸ�个类的实例支æŒ�æ ‡å‡†çš„æ¯”è¾ƒè¿�ç®—(比如>=,!=,<=,<ç‰),但是å�ˆä¸�想去实现那一大丢的特殊方法。
解决方案¶
Python类对�个比较�作都需�实现一个特殊方法�支�。
例如为了支æŒ�>=æ“�ä½œç¬¦ï¼Œä½ éœ€è¦�定义一个 __ge__() 方法。
尽管定义一个方法没什么问题,但如果è¦�ä½ å®žçŽ°æ‰€æœ‰å�¯èƒ½çš„æ¯”较方法那就有点烦人了。
装饰器 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__() ,它就能支�所有的比较�作:
# Build a few houses, and add rooms to them
h1 = House('h1', 'Cape')
h1.add_room(Room('Master Bedroom', 14, 21))
h1.add_room(Room('Living Room', 18, 20))
h1.add_room(Room('Kitchen', 12, 16))
h1.add_room(Room('Office', 12, 12))
h2 = House('h2', 'Ranch')
h2.add_room(Room('Master Bedroom', 14, 21))
h2.add_room(Room('Living Room', 18, 20))
h2.add_room(Room('Kitchen', 12, 16))
h3 = House('h3', 'Split')
h3.add_room(Room('Master Bedroom', 14, 21))
h3.add_room(Room('Living Room', 18, 20))
h3.add_room(Room('Office', 12, 16))
h3.add_room(Room('Kitchen', 15, 17))
houses = [h1, h2, h3]
print('Is h1 bigger than h2?', h1 > h2) # prints True
print('Is h2 smaller than h3?', h2 < h3) # prints True
print('Is h2 greater than or equal to h1?', h2 >= h1) # Prints False
print('Which one is biggest?', max(houses)) # Prints 'h3: 1101-square-foot Split'
print('Which is smallest?', min(houses)) # Prints 'h2: 846-square-foot Ranch'
讨论¶
其实 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
å½“ç„¶ï¼Œä½ è‡ªå·±åŽ»å†™ä¹Ÿå¾ˆå®¹æ˜“ï¼Œä½†æ˜¯ä½¿ç”¨ @total_ordering å�¯ä»¥ç®€åŒ–代ç �,何ä¹�而ä¸�为呢。