前言:作者在学习python面向对象时,遇到一个自定义类重写运算符方法的问题,卡了将近两个小时,下面分享给小伙伴们。
踩坑代码
import random
class Card:
"""牌"""
# 牌的花色
suites = "♠♥♣♦"
# 牌的面值
faces = ["3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"]
def __init__(self, suite: str, face: str):
self.suite = suite
self.face = face
def __repr__(self):
return f"{self.suite}{self.face}"
def __lt__(self, other):
"""牌的比较方式"""
# 根据牌面值在faces列表中索引的位置比较
return Card.faces.index(self.face) < Card.faces.index(other.face)
class Poker:
"""扑克"""
def __init__(self):
self.cards = [Card(suite, face) for suite in Card.suites for face in Card.faces]
def shuffle(self):
"""洗牌"""
random.shuffle(self.cards)
if __name__ == "__main__":
poker = Poker()
poker.shuffle()
poker.cards.sort(key=lambda x: (x, Card.suites.index(x.suite)))
print(poker.cards)
输出如下
[♦3, ♠3, ♣3, ♥3, ♣4, ♦4, ♥4, ♠4, ♣5, ♦5, ♥5, ♠5, ♠6, ♥6, ♦6, ♣6, ♣7, ♥7, ♦7, ♠7, ♥8, ♠8, ♣8, ♦8, ♥9, ♣9, ♦9, ♠9, ♠10, ♣10, ♦10, ♥10, ♣J, ♥J, ♦J, ♠J, ♠Q, ♣Q, ♦Q, ♥Q, ♠K, ♦K, ♥K, ♣K, ♦A, ♠A, ♥A, ♣A, ♦2, ♠2, ♣2, ♥2]
期望输出如下:
[♠3, ♥3, ♣3, ♦3, ♠4, ♥4, ♣4, ♦4, ♠5, ♥5, ♣5, ♦5, ♠6, ♥6, ♣6, ♦6, ♠7, ♥7, ♣7, ♦7, ♠8, ♥8, ♣8, ♦8, ♠9, ♥9, ♣9, ♦9, ♠10, ♥10, ♣10, ♦10, ♠J, ♥J, ♣J, ♦J, ♠Q, ♥Q, ♣Q, ♦Q, ♠K, ♥K, ♣K, ♦K, ♠A, ♥A, ♣A, ♦A, ♠2, ♥2, ♣2, ♦2]
问题分析
列表的sort方法,key参数接受一个函数,将列表中的每个元素都作用于该函数,并以该函数的返回值排序。
该函数可以有多个返回值,当第一个返回值不相等时,直接以第一个返回值排序,如果相等,则继续比较第二个返回值,以此类推。
在上述代码中,由于在Card类中重写了__lt__()方法,想当然的认为,当两张牌数字相同时,会继续比较花色,即card1==card2。但实际上,由于没有重写__eq__()方法,默认继承自Object的__eq__()方法,该方法比较的是对象本身,card1!=card2,因此在调用sort()方法时,lambda表达式的第一个返回值永不相等,所以不会使用第二个返回值进行比较。
self.cards.sort(key=lambda x: (x, Card.suites.index(x.suite)))
解决办法
重写Card类的__eq__()方法,如下:
def __eq__(self, other):
return Card.faces.index(self.face) == Card.faces.index(other.face)
将上述代码加到Card类下,再次运行,得到期望的结果。