CS编程中Python是一种解释型、动态数据、面向对象类型的高级程序设计语言。 Python 解决问题的方式常常会随着时间的推移而发生改变。随着Python的演变,Python列表的计数方式也得到了发展。下面洋蜜蜂CS专业辅导机构给大家列举几种方法。
对列表中各项目进行计数有各种各样的方法,接下来我们将通过观察每一种方法的代码风格,来分析这些技术的不同之处。至于它们的性能,我们以后再考虑。
我们需要了解一些 Python 的历史来理解这些不同的方法。幸运的是,我们可以用 Python 的 __future__ 模块,坐上时光机。现在让我们坐上德罗瑞恩(注:即系列电影《回到未来》中的时间机器),驶向1997年。
if 语句
现在是 1997 年 1 月,我们使用的是 Python 1.4。有一个颜色列表,我们很想要知道每一种颜色分别出现了多少次。我们来使用字典看看。
注:我们没有用+=,因为增量赋值语句在 Python2.0 版之后才被添加进去。我们也没有使用 c in color_counts 语句,因为这个语句到 Python2.2 版本才可以使用。
运行上述代码后,我们可以看到 color_counts 字典里包含了每一种颜色出现的次数。
这段代码很简单。通过循环遍历每一种颜色,检查每种颜色是否已经出现在字典中,如果还没有,把它添加到字典中。如果已经出现,那么把它的数量增一。
我们也可以按照下面的方式来写:
对于稀疏列表(没有很多重复颜色的列表),这种方式也许会有一点点慢,因为在 for 循环里需要执行两条语句。但是我们不担心它的性能,我们考虑的是它的代码风格。深思熟虑之后,我们决定使用新版本的代码。
try-except语句
现在是 1997 年 1 月 2 日,我们仍然在使用 Python 1.4。某天的早晨,我们醒来后突然意识到,我们本来应该按照“先斩后奏” 的方式去实践(这种方式更符合 Python 的思想),但实际上,我们是按照“三思而后行”的想法在编写代码。现在按照“先斩后奏”的方式,把我们的代码重写成一个 try-except 的块语句:
这段代码试着为每一种颜色的数量增一,但是如果这种颜色还没有出现在字典中,就会产生 KeyError 错误,那么该种颜色的数量就被初始化为 1。
get 方法
现在是 1998 年 1 月 1 日,Python 已经升级到 1.5 版本。我们决定用字典中的 get 方法来重写代码。
这段代码循环遍历每一种颜色,每次循环从字典中获得当前颜色的计数,默认计数为零,然后计数加一,最后把新值赋给这个字典的键,也就是颜色。
这段代码很棒的是 for 循环里只有一行语句,但是我们并不确定这是不是更加符合 Python 的风格。我们觉得也许这次的改进显得太智能了,所以我们决定将这次的改进还原。
setdefault 方法
现在是 2001 年 1 月,我们已经在使用 Python 2.0 版。在 Python 2.0 版中,字典里新添加了 setdefault 的方法。于是我们决定用 setdefault 的方法和 += 的增量运算符来重写代码:
在每次循环里,不管 setdefault 的方法是否会被用到都会被调用一次,但是这次的更改可读性更强,而且比之前的方法更符合Python的代码风格,因此我们决定保留这次更改。
fromkeys方法
现在是 2004 年 1 月 1 日,我们在使用 Python 2.3。听说字典里添加了一种新的 fromkeys 方法,这种方法可以从序列中获取键值来创建字典。我们用这个新方法来重写代码:
这段代码用颜色作为键创建了一个新的字典,并且每种颜色的数量被初始化为0。 这种方式可以直接增加每一种颜色的数量,不需要担心这种颜色有没有被包含到字典中。这段代码没有检查和例外情况的处理,我们认为这是一次改进,因此我们保留这次更改。
集合
现在是 2005 年 1 月 1 日,我们在使用 Python2.4。我们意识到现在可以使用集合(在 Python 2.3 版时发布,内置在 Python 2.4 版)和链表(在 Python 2.0 版时发布)来解决计数问题。再思考之后,我们突然想起生成器表达式也只是在 Python 2.4 时才公布,因此我们决定使用生成器表达式中的一种来进行计数。
注:我们没有使用字典解析,因为字典解析到 Python2.7 版才可以使用。
这个方法不错,只用了一行代码。但是这符合 Python 的风格吗?
我们记得在《Python 之禅》中,从 python 列表的邮件线程开始介绍,到 Python 发展到 2.2.1 版时结束。在我们的交互式解释器中输入 import this:
这段代码的复杂度是 O(n2),与复杂度为 O(n) 的代码相比,这段代码的美观度和可读性更差。这次的改变只是一次很有趣的实验,但是这种一行式的方法更不符合 Python 的风格。因此我们决定将这次改变恢复原状。
defaultdict 方法
现在是 2007 年 1 月 1 日,我们在使用 Python2.5。我们刚刚发现 defaultdict 已经出现在 Python 的标准库中了。我们可以使用 defaultdict 将字典中的值初始化为 0。我们用 defaultdict 来重写这段代码
for 循环现在相当简单了。现在几乎符合 Python 的代码风格了。
在这段代码中,我们发现变量 color_counts 虽然跟字典不太一样,但是它继承了字典所有的映射功能。
我们没有把 color_counts 这个类似于字典的对象转换成字典的格式,因为我们觉得以后的代码会更加的动态。
计数
现在是2011年1月,我们在使用Python 2.7。 我们了解到 defaultdict已经不是最符合 python 风格的计数方式了。在 Python 2.7 版的标准库中出现了一个 Counter 类,它可以为我们做所有的工作。
还能变得更简单吗?这应该是最符合 Python 风格的代码了。
与 defaultdict 的方法一样,上面的代码返回一个类似字典的对象(实际上是字典的子类),这与我们的目的正好不谋而合,我们就使用这个方法了。
深思之后:性能
注意一下,我们并没有关注这些计数方法的运行效率。这些方法中大部分复杂度为 O(n),但是由于 Python 的实现方式不同,运行时间也有所差异。
尽管性能不是我们关注的主要方面,我还是很关心这些方法在 CPython 3.5.0 版下的运行时间。根据颜色在列表中出现的频率去观察每一种方法的运行时间是一件很有趣的事情。
洋蜜蜂CS辅导机构争当海外留学的引导者,创新式辅导模式与海外名校师资,旨在为学生学有所成,提供各方位的服务,包括课程辅导,选课咨询,写作辅导等服务。
更多CS课程资讯,详情可点开洋蜜蜂官网即可获得更多,如果有Python编程辅导需求,可以咨询24小时在线客服微信:yuff996,洋蜜蜂助你度过学习难关。