某同学应聘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. 在kotlin用jni调用c++的dll中踩的坑

    在kotlin用jni调用c++的dll中踩的坑 can't find dependents libraries 不是个有效的32位程序(或者是?????32??????) 常规检查 java 指针 ...

  2. Flutter 基础组件:图片和Icon

    前言 Flutter中,可以通过Image组件来加载并显示图片,Image的数据源可以是asset.文件.内存以及网络. ImageProvider 是一个抽象类,主要定义了图片数据获取的接口load ...

  3. Java向指定Excel写入读取数据

    今天在开发中遇到用户列表导入导出的功能实现,这里了解到使用POI函数库可以完成此任务!特此记录一下 POI Apache POI是Apache软件基金会开放的源码函数库,POI提供API给Java程序 ...

  4. windows鼠标右键添加快捷方式

    [win]+[R] 输入regedit 打开路径:计算机\HKEY_CLASSES_ROOT\DesktopBackground\Shell 创建应用文件,这里以putty为例 右键 Shell 新建 ...

  5. RandomForest 随机森林算法与模型参数的调优

    公号:码农充电站pro 主页:https://codeshellme.github.io 本篇文章来介绍随机森林(RandomForest)算法. 1,集成算法之 bagging 算法 在前边的文章& ...

  6. Spring Boot Scheduled定时任务特性

    SpringBoot中的Scheduled定时任务是Spring Boot中非常常用的特性,用来执行一些比如日切或者日终对账这种定时任务 下面说说使用时要注意的Scheduled的几个特性 Sched ...

  7. 【Android】编译报错 Annotation processors must be explicitly declared now 解决方案

    问题 在网上下载一个demo,因为版本久远,里面添加了本地 Butter Knife 的jar包,在编译时报错 Annotation processors must be explicitly dec ...

  8. 阿里云VOD(三)

    一.视频播放器 参考文档:https://help.aliyun.com/document_detail/125570.html?spm=a2c4g.11186623.6.1083.1c53448bl ...

  9. 生僻标签 fieldset 与 legend 的妙用

    谈到 <fieldset> 与 <legend>,大部分人肯定会比较陌生,在 HTML 标签中,属于比较少用的那一批. 我最早知道这两个标签,是在早年学习 reset.css ...

  10. CoeMonkey少儿编程第4章 变量

    点击这里,现在就开启CodeMonkey的趣味编程之旅. 目标 了解什么是变量 了解变量的命名规则 掌握如何使用变量 变量 什么是变量?顾名思义,变量就是可以变化的量. 和变量相对的是常量,即不可变化 ...