L = [ i*i fori inrange(5) ]

forindex, data inenumerate(L, 1):print(index, ':', data)

去除 import 语句和列表的定义,实现同样的功能,不使用 enumerate 需要 4 行代码,使用 enumerate 只需要 2 行代码。如果想把代码写得简洁优美,那么,大家要时刻记住:在保证代码可读性的前提下,代码越少越好。显然,使用 enumerate 效果就好很多。

(2)any

在内置函数中,sort、sum、min 和 max 是大家用得比较多的,也比较熟悉的。像 any 和 all 这种函数,大家都知道,并且觉得很简单,但是使用的时候就想不起来。我们来看一个具体的例子。

我们现在的需求是判断 MySQL 中的一张表是否存在主键,有主键的情况,如下所示:

mysql> show index from t;+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+| Table |Non_unique | Key_name |Seq_in_index | Column_name |Collation | Cardinality |Sub_part | Packed |Null | Index_type |Comment | Index_comment |+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+| t |0| PRIMARY |1| id |A | 0 |NULL | NULL || BTREE || |+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+1row inset (0.00sec)

我们再来看一个没有主键的例子,如下所示:

mysql> show index from t;+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+| Table |Non_unique | Key_name |Seq_in_index | Column_name |Collation | Cardinality |Sub_part | Packed |Null | Index_type |Comment | Index_comment |+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+| t |0| id |1| id |A | 0 |NULL | NULL || BTREE || || t |1| idx_age |1| age |A | 0 |NULL | NULL |YES | BTREE || |+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+2rows inset (0.00sec)

在这个没有主键的例子中,虽然没有显式地定义主键,但是它有一个非空的唯一索引。在 InnoDB 中,如果存在非空的唯一约束,那么,这一列将会被当做主键。综合前面两种情况的输出,我们知道,要判断一张表是否存在主键,不能通过是否存在一个 key_name 名为 PRIMARY 的索引来判断,而应该通过 Non_unique 为 0 和 Null 列不为 YES 来判断。

说完了需求,我们来看一下具体的实现。使用 pymysql 连接数据库,数据库中的每一行,将会以元组的形式返回,如下所示:

(('t', 0, 'PRIMARY', 1, 'id', 'A', 0, None, None, '', 'BTREE', '', ''),)

也就是说,我们现在要遍历一个二维的元组,然后判断是否存在 Non_unique 为 0,Null 列不为 YES 的记录。具体实现代码如下:

defhas_primary_key():forrow inrows:ifrow[1] == 0androw[9] != 'YES':returnTruereturnFalse

非常简单,但是,如果我们使用 any() 函数的话,代码将会更短。如下所示:

defhas_primary_key():returnany(row[1] == 0androw[9] != 'YES'forrow inrows)

利用动态语言特性写出简洁优美的代码

在上一节中, 我们介绍了一些利用 Python 语言特性来编写简洁优美代码的例子。这一节,我们来看一个利用 Python 语言高级特性的例子。Python 作为一门动态类型语言,与 C、C++、Java 等静态类型语言有着显著的区别。下面我们将介绍其中的一个高级特性,这个特性充分演示了动态类型语言与静态类型语言的差异。更多的 Python 语言高级特性,我们将在随后的章节中介绍。

在这个例子中,我们会收到很多不同的请求,对于不同的请求,调用不同的请求处理函数,这个需求如此常见,相信大家应该见过这样的代码:

ifcmd == 'A':process_a()elifcmd == 'B':process_b()elifcmd == 'C':process_c()elifcmd == 'd':process_d()else:raiseNotImplementException

对于接收消息并调用不同的处理函数来说,上面的代码是很直观、也很容易想到的。但是,这段代码存在一个比较严重的问题。随着消息增加,if 语句不断壮大,这段程序最后将变得无法维护。

很多优秀的开源项目也会有类似的需求,但是,它们会使用其他方法解决这个问题。例如,在 Redis 系统中,会使用字典保存命令到执行函数之间的映射关系。当接收到一条新的命令时,先判断该命令是否存在于字典中,如果不存在,则说明不支持该命令。如果存在,则通过命令名称从字典中获取函数的指针,并通过函数指针的方式去调用相应的处理函数。如下所示:

structredisCommandredisCommandTable[] = {{"get",getCommand,2,"rF",0,NULL,1,1,1,0,0},{"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0},{"setnx",setnxCommand,3,"wmF",0,NULL,1,1,1,0,0},{"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0},

我们也可以参照 Redis 的实现方式,使用字典保存命令与命令处理函数之间的映射关系。但是,在 Python 语言中,还可以做得更好。

Python 语言是一门动态类型语言,具有自省(introspection)的能力。所谓自省,就是可以编写程序来处理其他已有的程序。例如,对于这里的需求,可以先根据请求的名称,判断相应的处理模块是否具有对应的处理函数。如果有,则获取相应的处理函数,然后进行调用。这么说或许比较抽象,我们来看一个具体的例子。

假设现在有一个名为 Person 的类,该类只有一个 name 属性,此外,该类有一个名为 get_first_name 的方法和一个名为 get_last_name 的方法。如下所示:

classPerson(object):def__init__(self, name):self.name = namedefget_first_name(self):returnself.name.split()[0]

defget_last_name(self):returnself.name.split()[-1]

为了进行更好的说明,我们在 IPython 中进行功能演示。在 IPython 中导入 Person 这个类,并创建一个对象。如下所示:

In [1]: fromperson importPersonIn [2]: jason = Person('Jason Statham')

Python 是一门动态类型的语言,我们可以在程序中处理已有的程序。例如,我们可以通过 Python 内置的 dir 函数,查看 jason 这个对象的所有属性。如下所示:

In[3]: dir(jason)Out[3]:['__class__','__dict__','__doc__','get_first_name','get_last_name','name']

我们已经看到了 jason 这个对象拥有的属性,并且,Python 内置的 dir 函数会返回这些属性的列表。现在,我们想测试某个属性是否存在,如果对象存在这个属性,则获取这个属性。这个任务可以由 Python 内置的 hasattr 和 getattr 函数来完成。如下所示:

In[4]: hasattr(jason, 'get_first_name')Out[4]: TrueIn[5]: action = getattr(jason, 'get_first_name')

In[6]: action()Out[6]: 'Jason'

In[7]: action = getattr(jason, 'get_last_name')

In[8]: action()Out[8]: 'Statham'

在这段程序中,首先通过 hasattr() 函数来判断对象是否具有某个属性,然后,通过 getattr() 获取该属性。由于我们获取到的属性是一个方法,因此,可以直接进行调用。由此可见,无论我们想要获取 get_first_name还是 get_last_name,都可以通过 getattr() 获取到属性,然后进行调用。

上面这段程序对我们有什么启发呢?假设有一个类,这个类中对每一条请求都有对应的处理函数。简单起见,假设请求的名称和处理函数同名。那么,我们可以通过 hasattr() 函数判断客户端是否拥有相应的属性,如果没有,则说明客户端不支持该请求。如果有,我们可以通过 getattr() 获得该请求的处理函数,然后调用该函数进行处理。

在这个例子中,我们只应用了非常简单的 Python 自省能力。包括通过 hasattr() 方法判断对象是否具有相应的属性,通过 getattr() 获取对象的属性。使用 Python 的自省,不用像其他编程语言一样,使用一堆的 if / else 语句来处理不同的消息。也不用像 Redis 一样,专门维护一个字典来保存每个消息及其对应的处理函数。因此,提高了程序的可扩展性。

像写文章一样写代码

关于如何能够写出 Pythonic 的代码,我的观点是:不管用什么语言,都应该努力写出简洁优美的代码。如果不能,那推荐看看《重构》和《代码整洁之道》,虽然这两本书使用的是 Java 语言,但是,作者要传递的思想同样适用于 Python。此外,我也有以下经验传授给大家,希望能够帮助新同学快速地写出还不错的代码。

像写文章一样写代码

准确无歧义

完整无废话

注意排版以引导读者

注意标点符号以帮助读者

保证可读性的前提下,代码尽可能短小

下面,我们来看一个 “利用标点符号以帮助读者” 的例子。在 Python 里面,空行是会被忽略的,也就说,有没有空行,有多少空行,对 Python 解释器来说都是一样的。但是,有没有空行对程序员来说可就不一样了,会显著影响程序的可读性。

随机生成 1000 个 0~999 之间的整数,然后求它们的和。这里是没有空行的例子:

importrandomdefsum_num(num, min_num, max_num):i = 0data = []fori inrange(num):data.append(random.randint(min_num, max_num))total = 0foritem indata:total += itemreturntotalif__name__ == '__main__':printsum_num(1000, 0, 1000)

这里是有空行的例子:

importrandomdefsum_num(num, min_num, max_num):i = 0data = []fori inrange(num):data.append(random.randint(min_num, max_num))

total = 0foritem indata:total += item

returntotalif__name__ == '__main__':printsum_num(1000, 0, 1000)

读者可以用心感受一下这两段代码,代码一模一样,唯一的区别是第二段代码多了几个空行,有空行的代码,明显看起来更加舒适愉悦。在用汉语写作文的时候,老师一直教导我们要合理地使用标点符号,合理地分段。其实,写代码和写文章是一样的。写代码时,大家可以这样想象:换行是逗号,空一行是句号,空两行是分段。至于逗号,因为我们总是在一行中写一条语句,所以,逗号是可以忽略的,如果你在一行中写了多条语句,就好比在写作文的时候没有正确地使用逗号,也让人难以理解。如果你从来不空行,所有代码堆积在一起,就好比没有句号,让人读起来很累。同理,不分段也不是好习惯。

总结

所谓 Pythonic,其实并没有大家想得那么神秘,最终目的都是写出简洁优美的代码,其思想在各个语言中都是一样的。如果你用其他编程语言写不出简洁优美的代码,那么你也没办法用 Python 写出简洁优美的代码。如果你能用其他语言写出很好的代码,那么还是需要深入了解 Python 这门语言特有的一些语法,并能够充分利用这些语言特性。这样,才能够写出 Pythonic 的代码。

关于 Pythonic、关于 Python 语言的高级特性、关于编程中容易犯的错误,无法在一篇文章中详细介绍。如果读者在看完这篇文章以后,还有一种意犹未尽的感觉,那么,就跟随我一起来学习《Python高质量编程》吧!

作者介绍

赖明星,架构师、作家。现就职于腾讯,参与并主导下一代金融级数据库平台研发。有多年的 Python 开发经验和一线互联网实战经验,擅长 C、Python、Java、MySQL、Linux 等主流技术。国内知名的 Python 技术专家和 Python 技术的积极推广者,著有《Python Linux 系统管理与自动化运维》一书。

2019年第三届MySQL技术嘉年华将于5月25日上海举行,早鸟票仅99元,想听姜老师现场来讲讲自己与PG的爱恨情仇,以及其他大佬们的MySQL开源之道,莫要错过。点击下方阅读原文即可报名。会后我们也可以聊聊深圳与上海,聊聊房子车子,聊聊各种江湖八卦。

长期坚持原创真的很不容易,多次想放弃。坚持是一种信仰,专注是一种态度!点赞和转发是对作者最好的褒奖哟~~

PS:想要加入IMG微信群的同学(目前仅峨眉群有坑,少林、武当两群已满),可私信我微信82946772,备注:申请加入峨眉,猎头勿扰返回搜狐,查看更多

python好学吗1001python好学吗-怎样才能写出 Pythonic 的代码 #P1001#相关推荐

  1. python用什么软件编程1001python用什么软件编程-怎样才能写出 Pythonic 的代码 #P1001#...

    L = [ i*i fori inrange(5) ] forindex, data inenumerate(L, 1):print(index, ':', data) 去除 import 语句和列表 ...

  2. python open方法1001python open方法_怎样才能写出 Pythonic 的代码 #P1001#

    L = [ i*i fori inrange(5) ] forindex, data inenumerate(L, 1):print(index, ':', data) 去除 import 语句和列表 ...

  3. python发音1001python发音-怎样才能写出 Pythonic 的代码 #P1001#

    L = [ i*i fori inrange(5) ] forindex, data inenumerate(L, 1):print(index, ':', data) 去除 import 语句和列表 ...

  4. pythonic 代码_怎样才能写出Pythonic 的代码?

    近来,身边的一些Python 大牛们老是提到一个很时髦的词:Pythonic,但却很少人说得清楚它是个什么意思,搞得新童鞋一头雾水: 在我们周围有很多资深的工程师,用其他语言写过很多的代码,做过很多项 ...

  5. java好的代码_做java软件工程师,怎样才能写出好的代码?

    原标题:做java软件工程师,怎样才能写出好的代码? Java代码之于java程序员而言就是左膀右臂,java代码写的好的java程序员明显更是企业的欢迎,一个优秀的java程序员的考核标准之一也是看 ...

  6. 如何才能写出高质量代码

    提醒:在发布作品前,请把不需要的内容删掉. 你是否曾经为自己写的代码而感到懊恼?你是否想过如何才能写出高质量代码?那就不要错过这个话题!在这里,我们可以讨论什么是高质量代码,如何写出高质量代码等问题. ...

  7. 如何才能写出优质的代码?

    优秀的代码是如何编写而成的?相信每个人都有自己的答案.在本文中,我们不妨从更为直观的角度加以理解:"如何才能写出优质的代码?" 1. 确保代码易于阅读 不论什么代码,首先我们要关注 ...

  8. Java基础知识(一),打好基础才能写出高质量代码

    前沿:不管工作多久,基础永远是最重要的,好多大厂看的就是基础好不好,所以写代码的同时,基础知识还是要去理解和记忆的,坚持每天来看一点 Java基础.语法: java面向对象的特征有哪些方面? 1.抽象 ...

  9. 怎么样才能写出出色的代码

    初学者在接触Java编程的时候总会遇到一些情况,比如:跟着Java基础教程看过一遍后,自己写代码的时候却无从下手,写代码的时候经常遇到不懂的地方,如果停下来去详细了解,可能会花掉大量时间,如果跳过去, ...

最新文章

  1. 关于《关于一道C#上机题的一点想法》
  2. 24 年前的 IE 仍能在 Win10中运行,这无敌兼容性与你的代码比比?
  3. c#写图像tif gdal_C# GDAL显示TIF
  4. python自学网站推荐-有哪些值得推荐的Python学习网站?
  5. Python学习笔记:错误,测试,调试(起)
  6. python pandas缺失值处理_Pandas之缺失值处理
  7. opencv图像仿射变换和普通旋转
  8. 服务器重新部署踩坑记
  9. 【知识补充】对称加密、非对称加密、数字签名与DDoS攻击
  10. 小程序 | 微信小程序实现图片是上传、预览功能
  11. python之验证身份证号合法性的库:id_validator
  12. Java面向对象之继承、super关键字、方法重写
  13. WinSock Socket 池
  14. 6 岁就成“大厂团宠”,这门编程语言竟引 Linux、谷歌、亚马逊共“折腰” !
  15. java ojdbc6_JAVA JDBC在连接ORACLE数据库时出现ojdbc6.jar has no source 问题?
  16. java项目中用到的solr_Solr的原理及在项目中的使用实例.
  17. Java输入/输出流
  18. 学校计算机房使用登记制度,瑶风中学计算机房管理制度
  19. 简洁界面清爽让人非常舒服的一款短视频去水印微信小程序源码自带接口支持多种流量主
  20. 学嵌入式职业发展方向有哪些?

热门文章

  1. Sql Server 三种事务模式
  2. [USACO15JAN]踩踏Stampede
  3. cocos2d-x CCParticleSystem粒子系统
  4. 排错-Loadrunner录制打不开浏览器解决方法
  5. 以下哪一个不属于python语言的特点-以下不属于python语言特点的是( )_学小易找答案...
  6. 编程爱好者学vb还是python-高手,这是高手!推荐几个我常看的顶级技术类公众号...
  7. 数据分析 python 用途-Python 从爬虫到数据分析
  8. python能绘制统计图吗-Python数据科学(九)- 使用Pandas绘制统计图表
  9. python处理表格数据-基于Python快速处理PDF表格数据
  10. python个人项目-个人项目 python实现