理解了这三点,才敢说自己会写Python代码
某同学应聘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代码的更多相关文章
- 通俗理解TCP的三次握手
三次握手流程的本质,可以这么理解:TCP的三次握手其实是双方各一次握手,各一次确认,只是其中一次握手和确认合并在一起. 当然也可以更通俗的去理解: "喂,你听得到吗?" " ...
- 深入理解C#第三版部分内容
最近,粗略的读了<深入理解C#(第三版)>这本技术书,书中介绍了C#不同版本之间的不同以及新的功能. 现在将部分摘录的内容贴在下面,以备查阅. C#语言特性: 1.C#2.0 C#2的主 ...
- 如何理解TCP的三次握手协议?
• TCP是一个面向链接的协议,任何一个面向连接的协议,我们都可以将其类比为我们最熟悉的打电话模型. 如何类比呢?我们可以从建立和销毁两个阶段分别来看这件事情. 建立连接阶段 首先,我们来看看TCP中 ...
- 深入理解NIO(三)—— NIO原理及部分源码的解析
深入理解NIO(三)—— NIO原理及部分源码的解析 欢迎回到淦™的源码看爆系列 在看完前面两个系列之后,相信大家对NIO也有了一定的理解,接下来我们就来深入源码去解读它,我这里的是OpenJDK-8 ...
- 使用神经网络来识别手写数字【译】(三)- 用Python代码实现
实现我们分类数字的网络 好,让我们使用随机梯度下降和 MNIST训练数据来写一个程序来学习怎样识别手写数字. 我们用Python (2.7) 来实现.只有 74 行代码!我们需要的第一个东西是 MNI ...
- 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码
最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...
- 深入理解 GIL:如何写出高性能及线程安全的 Python 代码
深入理解 GIL:如何写出高性能及线程安全的 Python 代码 本文由 伯乐在线 - 郑芸 翻译.未经许可,禁止转载!英文出处:A. Jesse.欢迎加入翻译组. GIL对多线程的影响:http:/ ...
- 如果有三个Bool型变量,请写出一程序得知其中有2个以上变量的值是true
下面这篇文章是从StackOverflow来的.LZ面试的时候遇到了一道面试题:“如果有三个Bool型变量,请写出一程序得知其中有2个以上变量的值是true”,于是LZ做了下面的这样的程序: bool ...
- 页面三个txt加载联动省市县的代码,类似淘宝的收货地址的布局
页面三个txt加载联动省市县的代码,假如有一个树形的JSON,分别显示的省市县这时候三个TXT怎么做联动效果呢,这里用framework7为例HTML: <div class="lis ...
随机推荐
- Java 并发编程要点
使用线程 有三种使用线程的方法: 实现 Runnable 接口: 实现 Callable 接口: 继承 Thread 类. 实现 Runnable 和 Callable 接口的类只能当做一个可以在线程 ...
- .netcore 急速接入第三方登录,不看后悔
新年新气象,趁着新年的喜庆,肝了十来天,终于发了第一版,希望大家喜欢. 如果有不喜欢看文字的童鞋,可以直接看下面的地址体验一下: https://oauthlogin.net/ 前言 此次带来得这个小 ...
- HBase 底层原理详解(深度好文,建议收藏)
HBase简介 HBase 是一个分布式的.面向列的开源数据库.建立在 HDFS 之上.Hbase的名字的来源是 Hadoop database,即 Hadoop 数据库.HBase 的计算和存储能力 ...
- Django中一种常见的setting与账密保存/读取方式
前言 在查看别人Django代码的时候,发现很多的manager文件都是类似于 #!/usr/bin/env python import os import sys if __name__ == '_ ...
- 【Redis3.0.x】事务
Redis3.0.x 事务 基本概念 multi,exec,discard,watch 是 Redis 事务的基础,它们允许一步执行一组命令,有两个重要保证: 事务中的所有命令都被序列化并顺序执行.在 ...
- SDUST数据结构 - chap3 栈和队列
一.判断题: 二.选择题: 三.编程题: 7-1 一元多项式求导: 输入样例: 3 4 -5 2 6 1 -2 0 输出样例: 12 3 -10 1 6 0 代码: #include<bits/ ...
- XSS - Labs 靶场笔记(上)
上周在网上看到的一个XSS平台,刷一波<doge Less - 1: 1.进入主界面,由图二可知是GET请求,提交name=test,回显在页面 2.查看源代码可知 没有做任何过滤,显然存在反射 ...
- 使用jib-maven-plugin将Spring Boot项目发布为Docker镜像
目录 介绍 使用 总结 介绍 将spring boot(cloud)项目发布到docker环境作为镜像,一般常用的一个是com.spotify的docker-maven-plugin这个maven插件 ...
- CTS相关的几个表
TMSALOG/TMSALOGAR :STMS传输日志表 TMSCNFS:传输组 TMSCDOM:传输域 TMSCDES:传输目的地 TMSBUFTXT:传输请求的短文本和用户 TMSCSYS:tms ...
- numpy模块(详解)
重点 索引和切片 级联 聚合操作 统计操作 矩阵 什么是数据分析 是把隐藏在一些看似杂乱无章的数据背后的信息提炼出来,总结出所研究对象的内在规律 数据分析是用适当的方法对收集来的大量数据进行分析,帮助 ...