11 月 19 - 20 日 Apache Pulsar 社区年度盛会来啦,立即报名! 了解详情
写点什么

如何利用 Python 编写高质量软件

  • 2019-08-21
  • 本文字数:3032 字

    阅读完需:约 10 分钟

如何利用Python编写高质量软件

Python正成为一种越来越受欢迎的编程语言,这一切当然不是偶然的。它是当今最具可读性的编程语言之一;它拥有数量庞大且实用性极强的库;对于初学者来说,它是一种很好的入门语言选项。

但随着 Python 应用范围的快速增加,其缺点也暴露了出来:很多人利用 Python 编写出大量严谨度不高、未经注释且无法管理的代码,这些代码已经充斥在互联网上的各个角落。事实上,这些糟糕的代码可能带来严重的后果,它们甚至忽略了语言当中最根本的要求——风格“准则”。在本文中,我们将共同发现、处理这类问题。与此同时,通过自查防止编写出质量低下的 Python 代码。



可怕的 Python 代码,到底是怎么一回事?

让我们先通过一个实例,看看什么叫可怕的 Python 代码。对于常见的 Fizz-Buzz 难题,我们来看以下解法:



再来看另一种解决方案:



我认为区别是显而易见的,虽然二者只在空格方面有所不同,但与第二种解决方案相比,第一种显然比较烦人。


编写这套方案的人,显然认为 if 表达式与范围函数之间完全不需要空格。没错,Python 解释器能够跳过这些空白,但人脑却不行——其他人在阅读代码时,会因为表达式中没有使用空格而感到头晕目眩、甚至恶心呕吐!


这只是个小问题,下面再来看看大错误:



相比之下,更好的解决方法应该是:



在这里,我不只是在脚本当中添加了空格和新行,同时还对导入与数据变量进行了重新命名。


为什么要这么折腾?(一个真实的案例)


大家可能会想:


我何必要为一个小小脚本中的空格、换行符以及变量名费心?


答案很简单,这些代码不会只由您自己使用——您可能会在博客或者GitHub上分享代码,那么这种写法显然不够专业。其他人会发现如此密集的代码读起来非常闹心,其中使用的种种非主流导入名称以及毫无意义的变量名称,也会令他人感到不解。


就算您确定只有自己会使用这些代码,那么过一阵子回过头来再看,混乱的命名方式同样可能令您身陷困境。以下是现实生活中的一个实例:


有一次,我需要制作一份脚本,用于将 excel 表格从布局 A 转换为布局 B,同时保留其中的值不变。这似乎是一项很简单的工作,所以我也没动什么脑子,顺手开始编写代码。经过几个小时的编写,我发现这个问题并不像看起来那么简单,因为任务当中有着近 8000 份 excel 表格,所以性能就成了必须考虑的大前提。这很难,因为我只能靠自己解决问题。距离截止时间越来越近,绝望中的我开始编写质量低下的代码——变量名称?随便起。函数名称?跟过程毫无关系。最糟糕的是,我连注释都没写。简而言之,这些代码成了 1000 行无人能解的恐怖谜题。终于,我在截止时间之前完成了任务,觉得一切终于大功告成。这个破项目,不需要扩展、导入或者嵌入,以后我再也不用它了。遗憾的是,我想得太简单了,他们发现有些表格在转换之后,跟布局 A 没多大区别。因此,我不得不连续三次对代码进行扩展。


这是一段令人沮丧且极其耗时的经历。希望大家别重蹈我的覆辙。


如何处理糟糕的代码


再来说说更极端的情况,有时候我们需要在项目当中集成一个库或者一组文件,但它们的编写质量很差,这又该咋办?我们当然不想把这些代码添加到项目中来,不过如果真的需要,我建议大家对代码内容做一番分析。如果代码不多,那最好是从头开始重新编写。但如果重写的工作量过大,下面我就教大家几招“清理”绝技,让整个过程更轻松、更快捷。


1. 格式化与注释


建议大家先从这一步做起。首先,在必要的位置添加一个空的换行符,移除不必要的注释,用空格把运算符和值分开等等。这一步非常简单,相信大家都能轻松搞定。


2. 变量名称


首先,如果大家了解可能的值或者角色,则可以对变量进行重新命名。对于不那么明确的变量名称,请谨慎处理,另外最好充分利用自动更正、高级搜索以及替换功能等 IDE 提供的现成选项。如果我们连猜测都没有把握,那最好是查看值的函数来源。如果不清楚该函数的作用,先参考第 3 点。


3. 函数


我们需要了解函数返回的内容,及其可以使用的参数类型。同样,我建议大家在这一步使用 IDE。如果各位对 IDE 特别反感,也可以利用IPython模块对命令行进行自动更新、函数参数检查以及其它处理。另外,请务必确保函数名称的更改明确且合理,在必要时最好删除那些一次性函数。最后,注意检查代码库当中函数的使用位置。


如何利用 Python 编写良好代码


一般来说,在 Python 中编写出漂亮且可读的代码并不是什么难事,但有时候我们可能需要加快速度,或者认为代码只需要使用一次。无论如何,请记住,这种情况下写出的代码只有两种结果——要么被彻底删除,要么被随后重写。


一旦重写,耗费的不仅是大量时间,同时也会造成精力的浪费。


充分利用 Python 的功能


下面来看 Tim Peters 为 Python 写下的箴言:


Python 之禅

Tim Peters

Beautiful is better than ugly.

美胜于丑。

Explicit is better than implicit.

显优于隐。

Simple is better than complex.

简大于繁。

Complex is better than complicated.

繁强于乱。

Flat is better than nested.

平高于嵌。

Sparse is better than dense.

疏好于密。

Readability counts.

可读可贵。

Special cases aren’t special enough to break the rules.

准则为先。

Although practicality beats purity.

实用至上。

Errors should never pass silently.

除非必要,

Unless explicitly silenced.

报错当显。

In the face of ambiguity, refuse the temptation to guess.

若无把握,切勿妄断。

There should be one — and preferably only one — obvious way to do it.

最佳答案,一枝独然。

Although that way may not be obvious at first unless you’re Dutch.

初虽劳碌,收益终现。

Now is better than never.

早改好于晚改,

Although never is often better than right now.

晚改好于乱改。

If the implementation is hard to explain, it’s a bad idea.

实现过繁,当有所省。

If the implementation is easy to explain, it may be a good idea.

实现若简,当有所喜。

Namespaces are one honking great idea — let’s do more of those!

命名空间,当有所用。


很明显,Python 语言在设计层面就充分考虑到了开发者对于代码的整洁与优雅需求,这也成就了 Python 的独特优势。下面,我要向大家展示 Python 中的一些出色功能,可以帮助各位构建出更好、更清晰的代码。请注意,这份清单并不完整,仅供您参考。


参数传递


在其它编程语言中,调用具有大量参数的函数时,我们往往一头雾水,因为看不出这些参数是如何排序的。虽然函数定义可以解决问题,但有时我们根本无法访问该定义。下面请看:



在调用 foo 时,我们不能只根据参数的值对其进行命名(参数值取决于参数的顺序)。在这种情况下,大家需要找到该函数的定义,并查看参数的具体位置。这可能需要花点时间。


Python 提供了一种解决方案,允许大家按任意顺序调用带有参数名称及其值的函数,而无需严格按顺序使用参数值。具体如下:



这就让编程过程更快、更干净也更安全。读者能够了解第二项参数是什么,因此搞乱函数调用顺序的可能性也会大大降低。


迭代器


如果我们面对这样一个任务:有一个名为 names 的数组,使用对应的索引号打印其中的每个名称。大家可以像这样解决:



但更具 Python 风格的解决办法应该是:



这里对于迭代器的解释显然更为明确。


总结

编写软件,要求我们做出前瞻性思考并充分理解其他代码读者的感受。Python 是一种易于上手的语言,能够快速实现代码的共享与脚本编写。但是,我们必须考虑到代码读者的需求——可能是同事、朋友,也可能是几天后的自己。


原文链接:


How to write quality software with Python


2019-08-21 16:4410245

评论

发布
暂无评论
发现更多内容

【TcaplusDB知识库】[List表]批量删除列表指定位置数据接口说明

tcaplus

AWS Command Line Interface 使用S3入门

阿呆

AWS S3

如何突破职业瓶颈

FunTester

Go 性能测试 测试框架 FunTester 职业瓶颈

【TcaplusDB知识库】[Generic表]删除数据示例代码

tcaplus

【TcaplusDB知识库】[List表]读取列表指定位置数据示例代码

tcaplus

如何提高后台服务应用问题的排查效率?日志 VS 远程调试

Jerry Wang

node.js 后台开发 1月月更

【TcaplusDB知识库】[Generic表]扫描数据示例代码

tcaplus

java开发之SpringBoot转发和重定向

@零度

JAVA开发 springboot

【TcaplusDB知识库】[List表]读取列表所有数据示例代码

tcaplus

【TcaplusDB知识库】[List表]插入数据到列表指定位置示例代码

tcaplus

【TcaplusDB知识库】[List表]删除列表指定位置数据接口说明

tcaplus

大咖眼中的AI开源|王敏捷:深图在人工智能中的探索和研究

亚马逊云科技 (Amazon Web Services)

网络

【TcaplusDB知识库】[Generic表]异步扫描数据示例代码

tcaplus

高新技术企业几维科技加入龙蜥,为操作系统安全添砖加瓦

OpenAnolis小助手

Linux 开源

【TcaplusDB知识库】[List表]删除列表所有数据接口说明

tcaplus

一文了解登陆Hoo虎符的Moonbeam治理通证GLMR

区块链前沿News

Hoo 虎符交易所 Moonbeam GLMR

【TcaplusDB知识库】[List表]扫描数据示例代码

tcaplus

【TcaplusDB知识库】[List表]异步扫描数据示例代码

tcaplus

TCP socket和web socket的区别

Jerry Wang

前端 node,js 1月月更

【TcaplusDB知识库】[Generic表]读取数据示例代码

tcaplus

【前端】一文彻底学会Promise

恒生LIGHT云社区

JavaScript 前端 Promise

【TcaplusDB知识库】[Generic表]加减字段值示例代码

tcaplus

【TcaplusDB知识库】[Generic表]更新数据示例代码

tcaplus

【TcaplusDB知识库】[List表]替换列表指定位置数据接口说明

tcaplus

【TcaplusDB知识库】异步调用接口示例代码

tcaplus

【TcaplusDB知识库】[Generic表]替换数据示例代码

tcaplus

【TcaplusDB知识库】[List表]插入数据到列表指定位置接口说明

tcaplus

【TcaplusDB知识库】数据分批返回示例代码

tcaplus

【TcaplusDB知识库】[Generic表]根据部分Key字段值读取数据示例代码

tcaplus

【TcaplusDB知识库】[Generic表]批量读取数据示例代码

tcaplus

【TcaplusDB知识库】[Generic表]插入数据示例代码

tcaplus

如何利用Python编写高质量软件_编程语言_Martin Kondor_InfoQ精选文章