记列表sort方法的一次踩坑实录

前言:作者在学习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类下,再次运行,得到期望的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值