某同学应聘Python岗位被录用。上班第一天,Leader吩咐他写一个获取次日日期信息的函数。该同学信心满满地写下了这样一段代码, 然后就没有然后了。

import time
def get_next_date():
time.sleep(24*60*60)
return time.strftime('%Y-%m-%d')

当然,这只是一个段子,相信没有Python程序员真的会写出这样的代码。不过,很多时候,我们写出来的代码尽管功能满足需求,效率也还说得过去,但可读性较差,且难以维护,和人们通常所说的简洁优美相去甚远。

那么,怎样才能写出传说中的简洁优美的Python代码呢?前几天,我在Python学习群里征集一个Python小题目的答案,借以了解程序员的编程习惯,分析影响程序员写出Pythonic代码的主要原因,最终总结出三条秘诀。题目如下:二维列表转置。

严格讲,Python的列表并没有维度的概念。这里说的二维列表是指类似下面这样的列表。

[ [1, 2, 3],
[4, 5, 6],
[7, 8, 9] ]

请实现二维列表的转置(行列互换,首行变首列,尾行变尾列,如下所示)。

[ [1, 4, 7],
[2, 5, 8],
[3, 6, 9] ]

这个活动得到了同学们的热情支持,甚至有同学们使用Java语言提交了自己的答案。对于这些同学,除了表示感谢,我无法回报更多,只能在能力所及的范围内,为每人提供30分钟的一对一服务,比如,代写作业、答疑等。

这是我收到的众多答案中的一个,并且很有代表性。

>>> a = [[1,2,3], [4,5,6], [7,8,9]]
>>> a_copy = []
>>> a_temp = []
>>> a_size = len(a)
>>> a_item_size = len(a[0])
>>> for i in range(a_item_size):
for j in range(a_size):
a_temp.append(a[j][i])
a_copy.append(a_temp)
a_temp = [] >>> a_copy
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

阅读这段代码的时候,最感吃力的是我需要记住a_copy、a_temp 、a_size、a_item_size等中间变量,否则读不懂后面的代码。在适当的位置合理地使用中间变量或临时变量,会提高效率,增强代码地可读性,但是,不加限制地使用,则会降低代码的可读性,同时也会带来更多的风险。

对上面的代码稍加修改,并封装成函数,感觉顺眼了很多。

>>> def transpose(arr):
result, arr_len = list(), len(arr)
for j in range(len(arr[0])):
result.append(list())
for i in range(arr_len):
result[-1].append(arr[i][j])
return result >>> transpose([[1,2,3], [4,5,6], [7,8,9]])
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

在我收到的答案中,大约有70%和修改后的这段代码类似。不过,这段代码看起来还是有点啰嗦,不够简洁。如果使用列表推导式,则可以在一行之内完成转置。

>>> def transpose(arr):
return [[arr[i][j] for i in range(len(arr))] for j in range(len(arr[0]))] >>> transpose([[1,2,3], [4,5,6], [7,8,9]])
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

使用列表推导式,可以让代码更加紧凑,但会降低可读性,因此应限制使用。在所有收集到的答案中,有几位同学使用了列表推导式,还有两位同学使用了NumPy的数组转置。遗憾的是,没有一位同学写出下面这个我认为的最佳答案。

>>> def transpose(arr):
return list(zip(*arr)) >>> transpose([[1,2,3], [4,5,6], [7,8,9]])
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]

这个答案,用到了内置函数zip()和一颗星(*)解包魔法,代码简洁高效。想要写出这样经典的答案,有一个前提条件就是对Python的内置函数能够信手拈来。Python内置了七十多个常用函数,配合不同的参数,可以实现非常精妙的功能。比如,从包含重复元素的列表中找出重复次数最多的元素,可以用一行代码高效实现。

>>> arr = [7,3,5,3,6,7,3,5,6,3,5]
>>> max(set(arr), key=lambda x:arr.count(x))
3

最后,总结一下写出简洁优美的Python代码的三条秘诀:

秘诀第1条:合理使用中间变量或临时变量
秘诀第2条:适度使用列表推导式等语法特性
秘诀第3条:尽量使用Python的内置函数

理解了这三点,才敢说自己会写Python代码的更多相关文章

  1. 通俗理解TCP的三次握手

    三次握手流程的本质,可以这么理解:TCP的三次握手其实是双方各一次握手,各一次确认,只是其中一次握手和确认合并在一起. 当然也可以更通俗的去理解: "喂,你听得到吗?" " ...

  2. 深入理解C#第三版部分内容

     最近,粗略的读了<深入理解C#(第三版)>这本技术书,书中介绍了C#不同版本之间的不同以及新的功能. 现在将部分摘录的内容贴在下面,以备查阅. C#语言特性: 1.C#2.0 C#2的主 ...

  3. 如何理解TCP的三次握手协议?

    • TCP是一个面向链接的协议,任何一个面向连接的协议,我们都可以将其类比为我们最熟悉的打电话模型. 如何类比呢?我们可以从建立和销毁两个阶段分别来看这件事情. 建立连接阶段 首先,我们来看看TCP中 ...

  4. 深入理解NIO(三)—— NIO原理及部分源码的解析

    深入理解NIO(三)—— NIO原理及部分源码的解析 欢迎回到淦™的源码看爆系列 在看完前面两个系列之后,相信大家对NIO也有了一定的理解,接下来我们就来深入源码去解读它,我这里的是OpenJDK-8 ...

  5. 使用神经网络来识别手写数字【译】(三)- 用Python代码实现

    实现我们分类数字的网络 好,让我们使用随机梯度下降和 MNIST训练数据来写一个程序来学习怎样识别手写数字. 我们用Python (2.7) 来实现.只有 74 行代码!我们需要的第一个东西是 MNI ...

  6. 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码

    最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...

  7. 深入理解 GIL:如何写出高性能及线程安全的 Python 代码

    深入理解 GIL:如何写出高性能及线程安全的 Python 代码 本文由 伯乐在线 - 郑芸 翻译.未经许可,禁止转载!英文出处:A. Jesse.欢迎加入翻译组. GIL对多线程的影响:http:/ ...

  8. 如果有三个Bool型变量,请写出一程序得知其中有2个以上变量的值是true

    下面这篇文章是从StackOverflow来的.LZ面试的时候遇到了一道面试题:“如果有三个Bool型变量,请写出一程序得知其中有2个以上变量的值是true”,于是LZ做了下面的这样的程序: bool ...

  9. 页面三个txt加载联动省市县的代码,类似淘宝的收货地址的布局

    页面三个txt加载联动省市县的代码,假如有一个树形的JSON,分别显示的省市县这时候三个TXT怎么做联动效果呢,这里用framework7为例HTML: <div class="lis ...

随机推荐

  1. CentOS8_在线安装_网络源_网络镜像源填写格式_以及其他笔记

    CentOS8_在线安装_网络源_网络镜像源填写格式_以及其他笔记 转载注明来源: 本文链接 来自osnosn的博客,写于 2020-10-1. 参考: Centos8.0.1905 在线安装源选择 ...

  2. docker nginx 自定义配置容器

    准备 拉取nginx官方镜像 docker pull nginx etc/nginx/ 下新建目录 cert 和 conf cert 存放证书 conf 存放配置文件 mkdir /etc/nginx ...

  3. [C#] 老古董的 Microsoft Chart Controls 也可以进行数据预测

    我要先声明,这篇文章介绍到的内容虽说不是不能用,但玩乐成分居多,大家看看就好,不要太认真. 1. Microsoft Chart Controls 中的 FinancialFormula 在上一篇文章 ...

  4. WebApi 中请求的 JSON 数据字段作为 POST 参数传入

    使用 POST 方式请求 JSON 数据到服务器 WebAPI 接口时需要将 JSON 格式封装成数据模型接收参数.即使参数较少,每个接口仍然需要单独创建模型接收.下面方法实现了将 JSON 参数中的 ...

  5. 认识webservice

    1.为什么需要webservice? 目前还有很多商用程序继续在使用C++.Java.Visual Basic和其他各种各样的语言编写.现在,除了最简单的程序之外,所有的应用程序都需要与运行在其他异构 ...

  6. 编译安装 nginx -1.14.2

    编译安装 nginx -1.14.2 1 ) 下载nginx-1.14.2 源码包: wget http://nginx.org/download/nginx-1.14.2.tar.gz 2 ) 编译 ...

  7. 十一:WEB渗透必懂知识点

    简述WEB层面上的漏洞以及类型,具体漏洞的危害等级, 如何形成以及如何发现 右边权重大于左边 CTF,SRC,红蓝对抗,实战 简要说明以上漏洞危害 简要说课以上漏洞等级划分 简要说明以上漏洞重点内容 ...

  8. pyi文件是干嘛的?(一文读懂Python的存根文件和类型检查)

    参考资料: https://blog.csdn.net/weixin_40908748/article/details/106252884 https://www.python.org/dev/pep ...

  9. 关于SSRF与CSRF漏洞的解释

    目录 SSRF服务端请求伪造(外网访问内网) 1.SSRF形成原因 2.利用SSRF漏洞的目的 3.SSRF漏洞的用途 4.SSRF漏洞的特性 实例 5.如何挖掘SSRF漏洞 6.常用SSRF去做什么 ...

  10. 【Linux】iptables的内核模块问题大坑!

    系统环境 CentOS 6.5 今天本来可以平静的度过一天,正品味着下午茶的美好,突然接到防火墙iptables的报警. 进入到服务器中,执行下面的命令查看,结果报错 /etc/init.d/ipta ...