Courses

什么是 Python 之禅?
Python 之禅由十九条格言组成,用作 Python 设计的指导原则。实际上它原本应有二十条格言;但 Python 的创造者 Guido van Rossum 迄今仍未按 Python 之禅作者 Tim Peters 的设想补上最后一条。Guido 据称表示,缺失的第二十条格言是“Tim Peters 的某个离奇内部笑话”。
尽管少了一条,Python 之禅因其对 Python 程序员开发过程的深远影响,于 2004 年被标准化为 PEP 20。遵循 Python 之禅并非强制,但了解并牢记在心是值得建议的。如果您忘了这些要义,只需在 Python 解释器中运行 import this,便可轻松温习。
>>> import this
The Zen of Python, by 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!
本文将对每一条要义作进一步解读。
#1 美胜于丑
作为程序员,您的能力毋庸置疑。用代码解决问题并不容易,但作为 Pythonista,人们对您的期待更高。优美的代码胜过丑陋的代码。Python 崛起之快,部分正是因为它的易用性:简洁、可读、优雅。作为 Python 开发者,您有责任通过编写优美的代码来维护 Pythonic 标准。
什么是优美的代码?确实具有主观性——情人眼里出西施这类道理。但有个简单的经验法则:写干净、可读、便于他人理解的代码。比如:
"""
Initial code was created by Vishal Sharma
See: https://towardsdatascience.com/the-zen-of-python-a-guide-to-pythons-design-principles-93f3f76d088a
"""
def collatz(num):
if num % 2 == 0:
return num // 2
else:
return 3 * num + 1
number = input("Enter a number: ")
while number != 1:
number = collatz(int(number))
print(number)
"""
Enter a number: 5
16
8
4
2
1
"""
上面的代码能正常工作,但未必优美。我们的 collatz 函数里有个不必要的 else 分支,可以这样移除:
def collatz(num):
if num % 2 == 0:
return num // 2
return 3 * num + 1
因此,当您面前有两段都能运行的代码时,应选择更简单、更易读、更易理解的那一段。
#2 明确胜于含糊
把任何格言称为“自明”的做法都是大错特错——不过您仍会常见有人这么说。“明确胜于含糊”的要旨在于:冗长直白的代码优于隐晦间接的代码。尽可能确保代码的功能不被晦涩的语言掩盖。对您的程序一无所知的人,也应能看懂代码在做什么。
#3 简单胜于复杂
如果您的朋友饭后拿出高压清洗机洗碗,您大概会笑场。那不仅是个荒唐的方案,还很可能把盘子弄坏。同理,把高度复杂的解法用在简单的编程问题上,非常不切实际。没必要刻意把方案复杂化,即便您觉得那样更显“聪明”。这样做可能弊大于利,且在 Python 世界里并不受欢迎。
看看这段用于反转字符串的函数:
def reverse_string(string):
if len(string) == 1:
return string
else:
return reverse_string(string[1:]) + string[0]
string = "kurtis"
print(reverse_string(string))
"""
sitruk
"""
这段代码确实解决了问题,但不必要地复杂。如果您对 Python 有较好掌握,就知道用索引即可反转字符串。
string = "kurtis"
# annonymous function solution
reverse_string = lambda x: x[::-1]
# function solution
def reverse(string):
return string[::-1]
print(reverse_string(string))
print(reverse(string))
"""
sitruk
sitruk
"""
#4 复杂胜于繁复
用高压清洗机洗盘子是不切实际的:用自来水冲洗等简单方案更合适。但如果要清洗一辆 4x4 的路虎揽胜呢?前一条与本条共同提醒我们:同一个问题既可能用简单技术解决,也可能需要复杂技术。清洗 4x4 路虎并非简单问题,硬套洗碗的技术或许可行,但比起用高压清洗机更“繁复”。因此,应在可能时偏好简单而非复杂;可在简单失效或不切实际时,果断选择复杂方案——要知道“简单”的边界。
#5 扁平胜于嵌套
程序员热衷将事物按类别、子类别、子子类别来组织,以区分功能。听上去井井有条,但这种组织方式有时会带来更多困惑而非秩序。
把所有代码放在一个顶层模块里并无不妥:这意味着您无需像这样写 from spam.foo.bar.john.doe import chicken 来访问特定功能。子层级越多,代码越复杂。尽量在可行时保持扁平化结构。
#6 稀疏胜于密集
程序员通常被视为最聪明的人群之一,无需靠过度炫技来彰显智力。您最常听到的可能是“如何用 1 行代码完成[某个复杂任务]”。有时单行代码是合理的,但不要为了一行而牺牲可读性。
以这段代码为例:
"""
Code source Al Sweigart
See: https://inventwithpython.com/blog/author/al-sweigart.html0
"""
print('\n'.join("%i bytes = %i bits which has %i possible values." % (j, j*8, 256**j-1) for j in (1 << i for i in range(8))))
"""
1 bytes = 8 bits which has 255 possible values.
2 bytes = 16 bits which has 65535 possible values.
4 bytes = 32 bits which has 4294967295 possible values.
8 bytes = 64 bits which has 18446744073709551615 possible values.
16 bytes = 128 bits which has 340282366920938463463374607431768211455 possible values.
32 bytes = 256 bits which has 115792089237316195423570985008687907853269984665640564039457584007913129639935 possible values.
64 bytes = 512 bits which has 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095 possible values.
128 bytes = 1024 bits which has 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137215 possible values.
"""
这段代码确实能跑,但阅读体验极差:内容拥挤、难以理解。
来看把它写成稀疏风格后会怎样:
# Sparse example
bytes_and_bits = {j: j*8 for j in (1 << i for i in range(8))}
for bytes, bits in bytes_and_bits.items():
print(f"{bytes} bytes = {bits} which has {256**bytes-1} possible values")
"""
1 bytes = 8 which has 255 possible values
2 bytes = 16 which has 65535 possible values
4 bytes = 32 which has 4294967295 possible values
8 bytes = 64 which has 18446744073709551615 possible values
16 bytes = 128 which has 340282366920938463463374607431768211455 possible values
32 bytes = 256 which has 115792089237316195423570985008687907853269984665640564039457584007913129639935 possible values
64 bytes = 512 which has 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095 possible values
128 bytes = 1024 which has 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137215 possible values
"""
上面的代码更易读,且与单行版本实现完全相同的功能。
#7 可读性至关重要
如果您还没意识到,Python 特别看重可读性。写代码只需一次,但它很可能被多次阅读。鉴于此,在变量与函数命名中删去元音并非好主意:当您可以在 create_lst 与 create_list 之间选择时,请选后者。
#8 特例不足以破坏规则
Python(以及整个编程领域)充满了应当遵循的最佳实践。遵循最佳实践往往优于我行我素,因为后者常导致风格不一致、难以阅读的代码。
#9 然而实用性胜过纯粹性
第九条是第八条的延伸。没错,遵循最佳实践更好,但若为严格守规而牺牲可读性,同样会导致代码难以理解。因此,每条规则都可能有例外。如果您的解法更实用、更易读、更易理解,那么偏离既定最佳实践反而更好。
#10 错误不应悄然无声
所谓“静默错误”,是指程序返回错误码或 None,而非抛出异常。让程序在错误处崩溃要好过把错误静默掉并继续运行。从长远看,静默错误会让 Bug 更难追踪和修复。
#11 除非明确地将其静默
第十一条是第十条的延伸。在某些情况下,您可能确实希望忽略程序产生的错误。这时,最佳实践是明确地在代码中将该错误静默处理。
#12 面对歧义,拒绝拍脑袋猜测
计算机只会做我们让它做的事:如果代码行为不如您所愿,是因为它正按您的指令行事。盲目尝试各种方案直至某个凑巧可行,这不是好策略——您可能只是掩盖了问题而非解决它。请抵制这种冲动。相反,应当理清问题的逻辑,用批判性思维提出合适的解法。
#13 事情应该有且最好只有一种显而易见的做法
Perl 语言的格言是:“同一件事不止一种做法!”选择太多常会导致选择过载。当实现相同目标有多种写法时,类似的情况也会出现。您拥有了更大的编码自由度,但为读懂代码,现在必须了解所有可能写法:这种额外学习成本毫无必要。
#14 不过这种做法起初也许并不显而易见,除非您是荷兰人
这条体现了 Tim Peters 的幽默感:Python 语言的创造者、终身仁慈独裁者(BDFL)Guido van Rossum 是荷兰人。这是个玩笑,用来提醒我们:要理解并记住 Python 的语言规则,对除创造者之外的所有人来说都不容易。
#15 现在做总比永不做好
这条告诉我们:陷入死循环或卡死的代码,比不执行要更糟。
#16 尽管“永不”往往比“立刻”更好
承接上一条:与其立刻终止程序而得到错误结果,不如等待程序正确完成执行。
#17 如果实现难以解释,那就是个坏主意
仅仅自己能理解还不够——“我知道自己在说什么”并不能令人信服。编程是团队活动,若您无法向队友清楚解释实现方案,很可能是把问题搞得过于复杂了。
#18 如果实现容易解释,那也许是个好主意
不过,容易解释并不必然意味着代码是好的——它只意味着容易解释。代码也许仍不够理想,但至少说明您走在正确的方向上。
#19 命名空间是个大大的好主意——让我们多用点!
命名空间是 Python 中用于组织程序内对象名称的抽象。给定特定的命名空间与作用域,Python 能在您调用符号名时判定所指对象。这条格言所表达的,就是 Python 在底层组织符号名的方式相当出色。
结语
本文呈现了我们对 Python 之禅的理解——这些准则旨在激励 Python 程序员编写整洁、可读的代码。有人将其视为流畅编码的终极蓝图,也有人没那么严肃看待。我们建议您尝试将这些原则应用到自己的代码中,亲自体会它们如何改进您的工作。若您想进一步学习如何编写更高效的代码,不妨看看 DataCamp 的 Writing Efficient Python Code。