当前位置: 首页 > 后端技术 > Python

Python高手必读,作为一个精通规则的玩家

时间:2023-03-26 00:01:50 Python

编程,其实和玩电子游戏有一些相似之处。在玩不同的游戏之前,您需要了解每个游戏的不同规则。只有熟悉并灵活运用游戏规则,才能更有可能在游戏中取胜。编程也是如此。不同的编程语言也有不同的“规则”。大到是否支持面向对象,小到是否定义常量,编程语言的规则比大多数电子游戏要复杂得多。我们在编程的时候,如果直接把一种语言的经验应用到另一种语言中,往往达不到最好的效果。就像CS(反恐精英)高手在不知道规则的情况下玩绝地求生(PUBG)。虽然他的枪法可能无懈可击,但很有可能还没找到第一个敌人就倒下了。被躲在草丛中的敌人伏击。Python中的规则Python是一种乍一看很简单的语言,但随着您深入了解它会变得更加复杂。就拿Python中最重要的“对象”这个概念来说吧,Python为它定义的规则多到你记不住。例如,如果一个对象定义了str方法,您可以使用str()函数返回可读的名称定义。可以循环和迭代具有next和iter方法的对象。用bool方法定义的对象在进行布尔判断时会使用自定义逻辑……熟悉规则并让你的代码适应这些规则,可以帮助我们写出更地道的代码,事半功倍。接下来,让我们看一个关于适应规则的故事。案例:从两份旅行数据中获取人员名单一天,在一家专注于新西兰出境游的旅游公司,一位业务同事兴冲冲地来找我,说他从某位合作伙伴那里获得了两份重要的旅行证件。数据:所有到过“泰国普吉岛”的人及其联系方式所有到过“新西兰”的人及其联系方式的数据是JSON格式的,如下图:dataofpeoplewhohave去过普吉岛"Albert","last_name:"Potter","phone_number":702-249-3714,"date_visited:"2013-09-11"}......]每条数据有四个字段:lastname,名字,手机号码,旅行时间,商务同学根据这些数据做了一个(听起来很不合理的)假设:“去过普吉岛的人应该也对去新西兰旅行很感兴趣。”从这些数据中,我们需要找出那些去过普吉岛但没有去过新西兰的人,并向他们销售产品。第一次暴力尝试有原始数据和明确要求,接下来的问题是如何编写代码。靠着暴力,我很快写出了第一个方案:因为原始数据中没有“用户ID”这样的唯一标识,所以只能用“完全相同的姓名和电话号码”作为是否相同的判断人标准。find_potential_customers_v1函数先遍历所有去过普吉岛的人,再遍历新西兰的人。如果在新西兰的记录中没有找到完全匹配的记录,则将其作为“潜在客户”返回。虽然这个函数可以完成任务,但相信不用我说你也能找到。它有非常严重的性能问题。对于普吉岛的每条访问记录,我们需要遍历所有新西兰访问记录,试图找到一个匹配项。整个算法的时间复杂度是可怕的O(n*m)。如果新西兰的访问条目很多,执行起来会非常长。为了优化内循环性能,我们需要减少线性搜索匹配部分的开销。尝试使用集合优化函数如果你对Python有所了解,那么你一定知道Python中的字典和集合对象都是基于哈希表(HashTable)实现的。判断一个item是否在集合中的平均时间复杂度是O(1),非常快。因此,对于上面的函数,我们可以先尝试初始化一个新西兰访问记录的集合,然后搜索匹配部分可以变得非常快,函数整体的时间复杂度可以改为O(n+m).再来看新功能:在使用了集合对象之后,新功能相比老版本在速度上有了突破。不过这个问题的优化不止于此,不然文章标题应该改成:《如何使用集合提高程序性能》。重新思考问题让我们试着抽象地重新思考问题的本质。首先,我们有一个容器A,里面有很多东西(Phuket访问记录),然后我们有另一个容器B,里面有很多东西(新西兰访问记录),然后定义一个相等规则:“namematchesphone”。最后根据这个相等规则,求出A和B的“差集”。如果你对Python中的集合不是特别熟悉,我再介绍一下。如果我们有两个集合A和B,那么我们可以直接用A-B这样的数学运算表达式来计算它们之间的差值。所以,计算“所有去过普吉岛但没去过新西兰的人”其实就是一个集差运算。那么我们可以做些什么来将我们的问题放入集合的游戏规则中呢?使用集合的游戏规则在Python中,如果要将某物放入集合或字典中,必须满足一个基本条件:“这个东西必须是可散列的(Hashable)”。什么是“可散列”?例如,Python中的所有可变对象(如字典)都不是Hashable。当您尝试将字典放入集合时会出现此错误:所以,如果我们想使用集合来解决我们的问题,我们必须首先定义我们自己的“Hashable”对象:VisitRecord。要使自定义对象可哈希化,唯一要做的就是定义对象的哈希方法。一个好的哈希算法应该使不同对象之间的值尽可能唯一,这样可以将“哈希冲突”的概率降到最低。默认情况下,所有Python对象的哈希值都来自于它的内存地址。在这个问题中,我们需要自定义对象的哈希方法,使其使用(lastname,firstname,phone)元组作为VisitRecord类的哈希值的来源。自定义hash方法后,就可以正常将VisitRecord实例放入集合中了。但这还不够,为了使上述差异算法起作用,我们还需要实现eq特殊方法。eq是Python在两个对象相等时调用的特殊方法。默认情况下,只有当自己和另一个对象的内存地址完全相同时,它才会返回True。但在这里,我们重用了VisitRecord对象的散列,当它们相等时,它们被认为是相同的。完成适当的数据建模后,后续的差分计算就水到渠成了。新版函数只需要一行代码即可完成操作:提示:如果你使用的是Python2,那么除了eq方法外,你还需要自定义类的__ne__(判断不等式时使用)方法.