美文网首页python交流学习
错误笔记:覆写Python中的__cmp__

错误笔记:覆写Python中的__cmp__

作者: 78c40b03ee4e | 来源:发表于2019-03-11 16:02 被阅读1次

前言

最近,在做一个简单的排名函数时,我不小心踩到了Python语言的一个坑里。我花了很多时间才找出具体的原因。这是值得记录的。

具体功能要求如下:对500人进行前500名排名,每个人的分数只增加而不减少,当得分相同时,比较列表上的时间戳,得分第一的用户排名。

这个列表之前已经做过很多,一般来说,会先抽象一个TopItem对象,保存用户的点,以及名称、UUID和其他相关信息。然后,使用列表对象top保存500个有序元素,使用dict对象缓存保存从uuid到topitem的映射。由于python对象的reference属性,添加一个额外的dict对象不会增加topitem对象的副本,但都指向同一topitem对象,所以不会有大的内存问题。

因此,整个数据结构可能显示在下面的伪代码中:

class TopItem(object):
    def __init__(self, uuid, name, score, t):
        self.uuid = uuid
        self.name = name
        self.score = score
        self.t = t 


class TopStub(object):
    def __init__(self, tops):
        self.tops = copy.deepcopy(tops)
        self.cache = {}
        for item in self.tops:
            if item.uuid not in self.cache:
                self.cache[item.uuid] = item

小编推荐一个学python的学习qun 740,3222,34
无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享!

当玩家播放列表时,首先根据uuid从缓存中查找topitem对象,如果找不到该对象,则直接根据分数以二进制搜索的方式插入;如果找到对象topitem,则更新其分数、名称等信息,然后将其从top列表中删除,然后插入。在二进制搜索中(因为分数只增加或不减少,所以这里有优化)。空间)。
这个排名,计划需要很多能够处理相同的分数(比较时间戳),所以我自然会考虑重写topitem的cmp_u函数,这样你就可以直接使用<>比较topitem,写完代码后就不漂亮了。然后编写以下CMP_uuu函数:

class TopItem(object):
# see above
    def __cmp__(self, other):
        if self.score != other.score:
            return cmp(self.score, other.score)
        else:
            return cmp(other.t, self.t)


class TopStub(object):
# see above

在测试期间,我做了一个测试功能。我一次随机插入n个用户数据的随机分数,QA通过了测试。没问题。

直到它上线。

大约两个小时后,我发现排名完全混乱,出现了“分阶段下降”的现象,用户信息在排名中反复出现。

经过彻底的调查,发现问题出在“CMP”和“清单”上。远程的从_cmp_u的定义可以看出,如果两个顶项的得分和t相等,那么我们将判断两个顶项是相等的。名单。删除(item)删除与item相等的第一个元素。“CMP”的改写对平等判断有明显影响。也就是说,如果两个顶级项的整数和时间戳相等,那么列表中的顶级项可能是错误的。删除(项)步骤将发生,以便在排名中同时出现多个相同的用户信息。
写一段代码来验证:

def test():
    t1 = TopItem('uuid1', 'aaa', 80, 10) 
    t2 = TopItem('uuid2', 'bbb', 90, 11) 
    t3 = TopItem('uuid3', 'ccc', 90, 11) 
    t4 = TopItem('uuid4', 'ddd', 100, 11) 
    tops = [t4, t3, t2, t1] 
    print 'tops:', tops
    tops.remove(t2)
    print 'after remove t2:bbb'
    print 'tops:', tops

output:
tops: [(ddd,100,11), (ccc,90,11), (bbb,90,11), (aaa,80,10)]
after remove t2:bbb
tops: [(ddd,100,11), (bbb,90,11), (aaa,80,10)]

果然没错,我们想删除t2(bbb),但是却把和t2“相等”的t3(ccc)删除了。

那么接下来的修正也很简单:

def __cmp__(self, other):
        if self.score != other.score:
            return cmp(self.score, other.score)
        elif self.t != other.t:
            return cmp(other.t, self.t)
        else:
            return cmp(id(self), id(other))

run test again and output:
tops: [(ddd,100,11), (ccc,90,11), (bbb,90,11), (aaa,80,10)]
after remove t2:bbb
tops: [(ddd,100,11), (ccc,90,11), (aaa,80,10)]

总结

记得之前看一些Python的文章时,有人说过,对于双下划线开头的这些函数,除非你确切知道自己在干什么,否则不要覆写这些函数。当时我还不以为然:既然Python提供了这么多有意思的钩子,干嘛不用呢?现在我才明白。

另外,覆写cmp函数时,在最后一个else分支中,比较id是比较稳妥的做法。

最后,Python3已经废弃掉cmp函数,改为提供eq, lt等多个函数,进一步降低使用者犯错的几率。

原文来自:http://blog.guoyb.com/2017/09/02/python-cmp/
侵删

相关文章

  • 错误笔记:覆写Python中的__cmp__

    前言 最近,在做一个简单的排名函数时,我不小心踩到了Python语言的一个坑里。我花了很多时间才找出具体的原因。这...

  • python中__cmp__

    对 int、str 等内置数据类型排序时,Python的 sorted() 按照默认的比较函数 cmp 排序,但是...

  • 39-python中 __cmp__

    对int、str等内置数据类型排序时,Python的sorted()按照默认的比较函数cmp排序,但是,如果对一组...

  • 第9天,异常处理

    @(python)[笔记] 目录 一、错误和异常 程序中的错误分成两种 1.1 语法错误 这种错误,根本过不了Py...

  • 初学Python常见异常错误,总有一处你会遇到!

    初学Python常见异常错误,总有一处你会遇到! 初学Python常见错误 忘记写冒号 误用= 错误 缩紧 变量没...

  • Python异常处理

    参考 Python菜鸟教程错误与异常 Python 异常处理 错误和异常 Python中(至少)有两种错误:语法错...

  • UINavgationController中覆写preferr

    *UINavigationController不会将 preferredStatusBarStyle方法调用转给它...

  • UINavgationController中覆写preferre

    文章转载自:https://blog.csdn.net/qq_27633421/article/details/1...

  • python 3学习笔记[连载更新中]

    python 3学习笔记 注意:本笔记只适用于Python 3版本,如文档编写错误可以联系作者,QQ:462548...

  • 覆写

    概念:如果子类重写了父类:属性的覆盖与方法的覆写 方法的复写:子类定义了与父类方法名称,参数类型以及个数完全相同的...

网友评论

    本文标题:错误笔记:覆写Python中的__cmp__

    本文链接:https://www.haomeiwen.com/subject/sujbpqtx.html