某同学应聘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. Redis缓存篇(三)缓存污染

    上一讲介绍了缓存满了,通过内存淘汰机制来淘汰掉数据.如果有的数据一直滞留在缓存中,但又没有应用使用,时间长了,就可能会占据大部分的缓存空间. 今天我们来学习一下缓存污染,以及如何解决缓存污染. 缓存污 ...

  2. FastApi学习(一)

    前言 学习不止 正文 介绍 FastApi是PythonWeb框架的'新晋干员',虽然年轻但是很能打 目前已有 12k start GitHub 官网 为什么说他能打呢?它内部使用了 Python 的 ...

  3. springboot源码解析-管中窥豹系列之aware(六)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  4. docker迁入迁出mysql

    docker迁出mysql数据库 测试环境: docker服务器 mysql服务器 IP 192.168.163.19 192.168.163.16 操作系统 CentOS7.8 CentOS7.8 ...

  5. Docker 镜像仓库使用(六)

    阿里云docker 容器镜像服务: www.aliyun.com 1 服务开通 (开通的时候要求创建密码请牢记此密码) 2 创建命名空间 3 创建镜像仓库 4 linux 客户端登录 登录: dock ...

  6. Docker学习笔记之基本命令使用

    测试的环境为Ubuntu1804. 1. search命令搜索镜像 sudo docker search centos 搜索centos相关的镜像,可以看到第一个最多星的的centos是官方的镜像,而 ...

  7. java创建线程安全的类

    如果一个对象想要被多个线程安全的并发访问,那么这个对象必须是或线程安全的或事实不可变的或由锁来保护的. 1.java监视器模式 大多数对象都是组合对象.当从头开始构建一个类,或者将多个非线程安全的类组 ...

  8. python无法连接mysql,有个小坑,需要注意一下!

    尝试用python链接mysql数据库,按照教程里链接了小半夜,就是没有链接上,找了各种文章,最后发现是版本的问题,我想使用的模块是MySQLdb,刚刚去他们的官网看了一下,最近一次更新是2014年, ...

  9. 深度学习DeepLearning技术实战(12月18日---21日)

    12月线上课程报名中 深度学习DeepLearning(Python)实战培训班 时间地点: 2020 年 12 月 18 日-2020 年 12 月 21日 (第一天报到 授课三天:提前环境部署 电 ...

  10. 推荐几个学习Python的免费网站

    想要学好Python,只靠看Python相关的书籍是远远不够的!今天为大家分享几个实用的Python学习网站. 欢迎各位热爱Python的小伙伴进群交流:610380249群里有大佬哦,而且很热心,群 ...