【FCon上海】与行业领袖共话AI大模型、数字化风控等前沿技术。 了解详情
写点什么

怎样让你写的 Python 代码更优雅?

  • 2020-04-03
  • 本文字数:4125 字

    阅读完需:约 14 分钟

怎样让你写的Python代码更优雅?

AI 大模型超全落地场景&金融应用实践,8 月 16 - 19 日 FCon x AICon 大会联诀来袭、干货翻倍!


通常,当我们在学校学习时,编程美学不是一个关键问题。用 Python 写代码时,个人也会遵循自己的风格。然而,当我们必须花大把时间来理解一个人的隐式代码时,这项工作肯定不受欢迎,这种情况同样可能发生在别人阅读我们的代码时。所以,让我们聚焦 Python 之禅和一些改进技巧,从而解决问题。

Python 之禅?

对于此前没听说过的人,请在 Python 解释器中键入并执行import this,会出现由 Tim Peters 撰写的 19 条指导原则:


  1. 优美胜于丑陋;

  2. 明了胜于晦涩;

  3. 简单胜于复杂;

  4. 复杂胜于晦涩;

  5. 扁平胜于嵌套;

  6. 间隔胜于紧凑;

  7. 可读性很重要;

  8. 特例不足以特殊到违背这些原则;

  9. 实用性胜过纯粹;

  10. 永远不要默默地忽视错误;

  11. 除非明确需要这样做;

  12. 面对模棱两可,拒绝猜测;

  13. 解决问题最直接的方法应该有一种,最好只有一种;

  14. 可能这种方法一开始不够直接,因为你不是荷兰人;

  15. 做也许好过不做;

  16. 但不想就做还不如不做;

  17. 如果方案难以描述明白,那么一定是个糟糕的方案;

  18. 如果实现容易描述,那可能是个好方案;

  19. 命名空间是一种绝妙的理念,多加利用!


在这篇文章中,我将分享自己对这些格言的理解以及我学到的一些有用的 Python 技巧。

优美胜于丑陋

Python 具有语法简单、代码可读性强和命令类似英语等特点,这让编写 Python 代码比使用其他编程语言更容易、更高效。例如,使用or and|| &&构建语义相同的表达式:


# &&, ||if a == 0 && b == 1 || c == True:  # and, orif a == 0 and b == 1 or c == True:  # 这两个逻辑表达式在Python中是相同的# 从语义的角度来看,可以使用选择操作符来构造完全相同的表达式。
复制代码


此外,代码的布局和组成非常重要,有大量资源涉及这个主题。下面是最受欢迎也是我最喜欢的一个:PEP 8——Python代码风格指南


浏览完 PEP8 后,看看下面这些文章,其中展示了一些亮点和应用:



永远不要弄乱你的代码。要优雅而美丽。

明了胜于晦涩

在 Python 中,良好的命名约定不仅可以提升你的课堂成绩,而且还能让你的代码更明了。幸运的是,你能在PEP8中找到一些指导原则,我想在下面强调其中的一些要点。


  • 一般来说,避免使用以下名称:


  1. 太宽泛,如my_list

  2. 太冗长,如list_of_machine_learning_data_set

  3. 太模糊,如“1”、“I”、“o”、“O”。


  • 包/模块名应该全部小写:


  1. 首选使用一个单词命名;

  2. 当需要使用多个单词时,使用下划线分割它们。


  • 类名应遵循 UpperCaseCamelCase 规范

  • 变量\方法\函数应该采用小写(如果需要,用下划线分割)

  • 常量名必须全大写(如果需要,用下划线分割)


一切都必须清晰易懂。

简单胜于复杂

简单比复杂更难:你必须付出巨大艰辛,化繁为简。但这一切到最后都是值得的,因为一旦你做到了,你便能创造奇迹。——乔布斯


很多时候,在处理迭代器时,我们还需要保存迭代计数。Python 通过提供一个名为enumerate()的内置函数简化这一任务。以下是一种不成熟的方法,然后是推荐方法:


words = ['Hannibal', 'Hanny', 'Steeve']# 不成熟的方法index = 0for word in words:    print(index, word)    index += 1    # 推荐方法for index, word in enumerate(words):    print(index, word)
复制代码


另一个示例是使用内置的zip()函数,该函数创建一个迭代器,对来自两个或多个迭代器的元素进行配对。你可以使用它来快速有效地解决常见的编程问题,比如创建字典。


subjects = ['math', 'chemistry', 'biology', 'pyhsics']grades = ['100', '83', '90', '92']grades_dict = dict(zip(subjects, grades))print(grades_dict)
复制代码


化繁为简的能力就是消除不必要的东西,保留必要的东西。

复杂胜于晦涩

复杂(complex )和晦涩(complicated )的区别在于,复杂是指组件的系统层级,晦涩是指难度高。


有时候,尽管我们试图让任务变得简单和傻瓜化,结果可能仍然很糟。在这种情况下,编程优化变得很有必要,我最喜欢的学习方法是完成coding challenge websites上的工作。你可以查看其他人的解决方案,甚至能受到更好算法的启发。


对于入门,HackerRank提供了适合新手程序员的各种级别任务,这非常棒。之后,可以去尝试更专业的网站,比如CoderbyteTopcoder

扁平胜于嵌套

嵌套模块在 Python 中并不常见——至少我之前没有见过像module.class.subclass.function这样的东西——可读性不好。虽然在另一个子模块中构建子模块可能会减少代码行数,但我们不希望用户被不直观的语法所困扰。

间隔胜于紧凑

不要在一行中插入太多代码,这会给读者带来压力。建议最大行长度 79 个字符。这样,当使用代码评审工具时,编辑器窗口宽度限制才能很好工作。



使用 Python 从 Unsplash 下载图片

可读性很重要

代码的阅读次数比编写次数多。考虑下缩进,它让代码更容易阅读,比较下面的代码:


money = 10000000print("I earn", money, "dollars by writing on medium.")
money = 10_000_000print(f"I earn {money} dollars by writing on medium.")
复制代码


在本例中,代码结果相同,但是后一段代码通过使用下划线占位符和 f-string 提供了更好的可读性。在 Python 3.6 发布后,f-string 开始让格式化变得更简单,并且在处理包含更多变量的更长的句子时更强大。


一个作家的风格不应该在他的思想和读者的思想间设置障碍。

特例不足以特殊到违背这些原则

关键是为一般情况提供一贯支持,尝试将一个繁琐的项目重新组织成一个简单形式。例如,根据其功能,结构化类的代码或将其分类到不同的文件中,即使 Python 并不强迫你这样做。由于 Python 是一种多范式编程语言,解决问题的一个强大方法是创建对象,这就是所谓的面向对象编程


面向对象编程是一种组织程序结构的编程范式,让属性和行为可以被看作是单独对象。它的优点是直观和易于操作,许多教程都很好地解释了这些概念。

实用性胜过纯粹

这句格言与前一句相矛盾,它提醒我们保持它们之间的平衡

永远不要默默地忽视错误

放过错误最终会留下隐式 Bug,并且这些 Bug 更难被发现。Python 提供了健壮的错误处理,与其他语言相比,程序员使用该工具并不难。


try:    x = int(input("Please enter an Integer: "))except ValueError:    print("Oops! This is not an Integer.")   except Exception as err:    print(err)else:    print('You did it! Great job!')finally:    print('ヽ(✿゚▽゚)ノ') # 1.这段代码可能中断。# 2.如果出现值错误就会触发。# 3.处理值错误之外的错误。# 4.如果没有触发错误就执行。# 5.不管是否触发错误都执行。
复制代码


根据Python文档:“即使一个语句或表达式在语法上是正确的,在试图执行它时也可能会导致错误。”


特别是对于大型项目,我们不希望在耗时的计算后,代码崩溃。这就是异常管理的魅力所在。

除非明确需要这样做

在某些情况下,小错误不会困扰你。不过,也许你想捕获特定错误。要获得关于特定错误消息的更多细节,我建议阅读官方的内置异常文档并找到你需要的内容。

面对模棱两可,拒绝猜测

重要的是要不断学习,享受挑战,容忍歧义。我们都不知道最终会怎样。——玛蒂娜·霍纳


这句话优雅而抒情,但在编程中不是一个好的隐喻。歧义可能是指不清楚的语法、复杂的程序结构或触发错误消息的错误。例如,第一次使用numpy模块时的一个简单错误:


import numpy as np
a = np.arange(5)print(a < 3)if a < 3: print('smaller than 3')
复制代码


ValueError: 具有多个元素的数组的真值不明确,请使用 a.any()或 a.all()


如果执行上面代码,你将在输出中发现一个由 5 个布尔值组成的数组,表明值在 3 以下。因此,if语句不可能确定状态。消息中显示的内置函数.all()和.any()用于代替 And/Or。


import numpy as np
a = np.array([True, True, True])b = np.array([False, True, True])c = np.array([False, False, False])
print(a.all())print(a.any())
print(b.all())print(b.any())
print(c.all())print(c.any())
复制代码


输出表明,.all()仅在所有项都为True时才返回True,而.any()在有一项为True时就返回True

解决问题最直接的方法应该有一种,最好只有一种

想想为什么 Python 被描述为一种易于学习的编程语言。Python 具有非凡的内置函数/库和高度的可扩展性,它鼓励程序员优雅地编写代码。尽管有更多的解决方案可以提供灵活性,但对于同一个问题,它们可能会花费更多时间。



输入 import antigravity 并执行

当然这是没法一蹴而就的,除非你是荷兰人

Python 之父Guido van Rossum是一位荷兰程序员,他让这句格言变得无可争议。你不会声称自己比他更了解 Python……至少我不会。



照片来自 GitHub

做也许好过不做

你可以拖延,但时间不会,失去的时间一去不复返。——本杰明·富兰克林


对于那些像我一样患有拖延症,正在寻求改变的人,看看这个,和恐慌怪兽合作。


另一方面,这个格言的另一个方面是阻止你过度计划,这并不比看 Netflix 更有效率。


拖延和过度计划的共同特征就是“什么都做不了。”

不想就做还不如不做

“做也许好过不做”并不意味着计划没用。把你的想法写下来,设定一个要征服的目标,比不想就做要好。


例如,我通常在每个星期天花一个小时来制定我的周计划,并在睡觉前更新我明天的计划,看看有什么需要推迟的事情。

如果解决方案难以解释清楚,那一定很糟糕

回想一下“复杂胜于晦涩”的理念。通常,晦涩的代码意味着弱设计,特别是在像 Python 这样的高级编程语言中。


然而,在某些情况下,其领域知识的复杂性可能会让实现难以解释,而如何优化让其明晰易懂至关重要。这里有一个规划项目指南,可以给你提供帮助。

如果实现容易描述,那可能是个好方案

使设计(甚至人们的生活)更容易,即使背景知识可能很深刻,这是编程的专业知识,我认为也是编程中最困难的部分。


利用 Python 的简单性和可读性来实现一些疯狂的想法。

命名空间是一种绝妙的理念,多加利用!

最后但同样重要的是,命名空间是一组符号,用于组织各种对象,以便这些对象可以通过惟一的名称引用。在 Python 中,命名空间是由以下元素组成的系统:


  1. 内置命名空间:可以在不创建自定义函数或导入模块(如print()函数)的情况下调用。

  2. 全局命名空间:当用户创建一个类或函数时,将创建一个全局命名空间。

  3. 局部命名空间:局部作用域中的命名空间。



命名空间关系图


命名空间系统可以防止 Python 模块名称之间产生冲突。


英文原文:


How to Make Your Python Code More Elegant


2020-04-03 22:475435
用户头像

发布了 704 篇内容, 共 422.3 次阅读, 收获喜欢 1519 次。

关注

评论

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

DC EP要统一“ 世界度量衡”,数字货币打开财富大门

CECBC

大型前端项目 DevOps 沉思录 —— CI 篇d

CODING DevOps

ci DevOps 持续集成 工作流

低代码发展正当时,中国将取代美国成为低代码开发的全球领导者

金小K

RPA 低代码 低代码开发 低代码平台

🏆【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起实践RocketMQ的服务搭建及配置操作

洛神灬殇

消息队列 Apache RocketMQ 12月日更

工作不喜欢,但不得不暂时干着,很痛苦,怎么办?

石云升

学习笔记 28天写作 12月日更

声网发布教育新品:灵动课堂全球覆盖学生超400万,互动白板首创H5课件

声网

人工智能 代码

ONES 与极狐(GitLab)战略合作,强强联手推动 DevOps 发展

万事ONES

DevOps SaaS ONES #GitLab

EasyRecovery如何恢复游戏——英雄联盟

淋雨

数据恢复 EasyRecovery

33 K8S之访问控制

穿过生命散发芬芳

k8s 28天写作 12月日更

自定义View:使用二阶贝塞尔曲线绘制正弦函数

Changing Lin

12月日更

Android C++系列:Linux守护进程

轻口味

c++ android 28天写作 12月日更

智慧社区管理系统,智慧社区一体化平台

电微13828808271

元宇宙赛道以百万年薪“抢人”未来五大类人才最紧俏

CECBC

Python Qt GUI设计:QPrinter打印图片类(基础篇—21)

不脱发的程序猿

Python PyQt GUI设计

一个基于HTML的可定制轮盘——帮你告别选择困难症

海拥(haiyong.site)

html 大前端 28天写作 签约计划第二季 12月日更

【Promise 源码学习】第十篇 - Promise.prototype.catch 和 Promise.prototype.finally 的实现

Brave

源码 Promise 12月日更

区块链电子合同签署平台,区块链智能合同优势

电微13828808271

创业研发团队的组织建设-人才培养

wood

创业 人才培养 28天写作

小企业如何落地elk日志收集系统

小鲍侃java

内容合集 签约计划第二季

质量服务“一站式”平台搭建,NQI一站式云服务平台

电微13828808271

在Linux系统发行版(以CentOS7为例)上部署ElasticSearch集群并启动Kibana和Logstash

为自己带盐

Centos 7 28天写作 Elastic Search 签约计划第二季 12月日更

Istio 实践手册 |服务网格框架对比

xcbeyond

istio 28天写作 12月日更 Istio 实践手册

基于云的技术架构设计实践-第2篇

hackstoic

监控系统 签约计划第二季

随笔—写作

圣迪

让每块火腿都留下“数字痕迹”!西媒:区块链将用于保护食品安全

CECBC

中年人的沉重3

张老蔫

28天写作

MySQL探秘(三):InnoDB的内存结构和特性

程序员历小冰

MySQL 28天写作 12月日更

单例模式

卢卡多多

单例模式 28天写作 12月日更

【LeetCode】亲密字符串Java题解

Albert

算法 LeetCode 12月日更

云编辑 | 使用 Cloud Studio 在线撰写预览并发布 Hugo 博客

宋天伦

CloudIDE Hugo Cloud Studio

实用机器学习笔记二:数据获取

打工人!

机器学习 学习笔记 12月日更 实用机器学习

怎样让你写的Python代码更优雅?_语言 & 开发_Hannibal Liang_InfoQ精选文章