购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第1章
Python的哲学

我一直秉持这样一个观点:最好的学习Python的路径并不是从语言本身开始,而是从Python的哲学开始。要写出好的Python代码,必须先理解Python是什么。这就是本章的重点。

1.1 到底什么是Python?

Python是由荷兰程序员Guido van Rossum创造的一门编程语言,于1991年发布。Python这个名字并不是指蟒蛇,而是指电视节目 Monty Python’s Flying Circus (这一点本身就能告诉你很多关于这门语言的思想)。这个项目最初是一个业余项目,但现在已经成为最受欢迎的计算机语言之一。

从技术角度来看,Python是一门高级的通用编程语言,它支持过程式编程、面向对象编程和函数式编程等编程范式。

Python爱好者总是喜欢强调它的可读性和简洁性,这让人们在初次接触Python时有一种“魔法”的感觉。这也导致出现了一些对新手来说并不是很有用的建议:“Python很简单,它就是伪代码!”

这并不是完全正确的。不要让Python的自然可读性欺骗了你:Python确实很独特,受到了很多其他语言的影响,但它往往和其他语言没有太多相似之处。要真正掌握它,你必须从它本身开始,而不是用它和其他语言进行深入比较。这正是本书要做的事情。

最重要的是,Python是一种信念。这种信念由一群不同背景的极客构筑,他们之所以能够这么做,只是因为他们对于构建一门优秀的编程语言有着大胆的想法。当你真正理解Python时,它就会改变你的整个视角。你是这个信念的一部分,这个信念已经有了自己的生命。

正如Guido van Rossum在他著名的“国王节演讲”(King’s Day Speech,详见附录C)中所说的那样:

我认为最重要的想法是,Python是在互联网上开发的,完全开放,由一群志愿者(但并非业余人士!)开发,他们对这门语言充满了激情和主人翁精神。

1.2 破除误解:Python不是什么

人们对Python有很多的误解,其中一些误解导致人们在某些应用场景下想方设法避免使用Python,甚至完全不使用Python。

1.2.1 误解1:Python仅仅是一种脚本语言

在我看来,“脚本语言”是讨论编程语言时最令人讨厌的术语之一。它暗示着这门语言不适合编写“真正”的软件(见误解5)。

Python是一门图灵完备的语言,这意味着你可以用Python实现任何其他编程语言,然后就可以执行用那种语言编写的任何程序。

换句话说,任何其他编程语言能做的事情,Python都能做到。这是否容易,乃至于是否可行,取决于你想要做什么。

1.2.2 误解2:Python很慢

通常来说,人们很容易认为,像Python这样更高级的或解释型编程语言比C语言这样更低级的或编译型编程语言慢。事实上,这取决于语言的实现方式和使用方式。在本书中,我们将介绍几个与提升Python代码性能相关的概念。

Python解释器的默认实现CPython是用C语言写的,在执行效率上的确会比原生机器码低。然而,有各种各样的库、技术以及其他Python解释器的实现(包括PyPy),它们的整体性能都要好得多(参见第21章),甚至接近原生机器码的执行效率。

综上所述,你应该弄明白性能是如何影响你的项目的。在大多数情况下,Python的性能已经足够好,可以作为应用开发、数据分析、科学计算、游戏开发、Web开发等领域的首选语言。CPython的性能缺陷通常只会在你面对一些特定的、对性能要求极高的场景时才会成为问题。即使如此,也有办法解决这些问题。对大多数项目来说,Python的基本性能已经足够了。

1.2.3 误解3:Python不能被编译

Python是一门“解释型语言”,这意味着代码在运行时由语言的解释器读取、解释和执行。运行Python项目的最终用户通常需要安装Python解释器。

与之对应的是所谓的“汇编型语言”,比如C语言、C++和FORTRAN。在这些语言中,编译的最终结果是机器码,可以直接在任何兼容的计算机上执行,而不需要安装其他程序(或者将其与代码捆绑在一起)。

有关“编译型语言”这个术语的争议非常多,这就是为什么我喜欢使用“解释型语言”和“汇编型语言”两个术语来区分它们。实际上相关的争论可以说是个无底洞。

很多开发者认为Python代码不能编译成机器码,这似乎是显而易见的结论。事实上,Python代码可以编译成机器码,尽管这种情况很少见。

如果你想尝试一下这条路径,那么这里有几个选项。在UNIX系统中,内置的Freeze工具可将Python字节码转换为C语言数组,然后将这些C语言代码汇编为机器码。但是这并不会产生真正的汇编Python代码,因为Python解释器仍然需要在幕后被调用。Freeze只能在UNIX系统中工作。cx_Freeze工具以及Windows系统中的py2exe所做的事,与Freeze类似。

想要真正地将Python代码编译为机器码,你必须使用中间语言。Nuitka可以用于将Python代码转换为C语言或C++代码,然后将其汇编为机器码。你也可以使用VOC将Python代码转换为Java代码。Cython则允许将特殊形式的Python代码转换为C语言代码,尽管它主要面向用C语言编写Python扩展。

1.2.4 误解4:Python在后台编译

Python解释器会将原始代码编译为稍后执行所需的字节码。解释器包含一个虚拟机,它会像CPU执行机器码一样执行Python字节码。有时,出于性能上的考虑,解释器会提前将代码转换为字节码,并生成包含字节码的 .pyc文件。虽然这在某种意义上是“编译”,但将代码编译为字节码与将代码编译为机器码之间存在一个关键区别:字节码仍然需要通过解释器执行,而机器码可以直接执行,不需要额外的程序。(从技术上讲,“编译”为机器码称为汇编,尽管这种区别往往被忽略或忽视。)

在实践中,大多数Python项目以源代码或Python字节码的形式分发,这些代码在安装于用户计算机上的Python解释器中运行。有时,以标准的可执行文件的方式进行分发更为可取,例如在终端用户计算机上安装或在闭源项目中安装。对于这些情况,Python社区提供了PyInstaller和cx_Freeze等工具。这些工具不会编译代码,而是将Python源代码或字节码与解释器捆绑在一起,以便独立执行(请参阅第18章)。

1.2.5 误解5:Python不适合大型项目

我经常听一些开发者说:“如果能将整个项目都放在一个文件中,那么Python就很有用。”这种“吐槽”通常基于这样的误解:具有多个文件的Python项目结构令人头大 。这确实是趋势,但只是因为很少有开发者知道如何正确地构建Python项目。

实际上,Python项目的结构比C++和Java项目的结构要简单得多。一旦开发者理解了包、模块和导入系统(请参阅第4章)的概念,就可以轻松处理多个代码文件。

这个误解的存在还有另外一个原因:Python是动态类型的,而不像Java或C++那样是静态类型的,一些人认为这使得重构变得更加困难。实际上,如果开发者知道如何使用Python的类型系统,而不是与之抗争,这就不是问题(请参阅第5章)。

1.3 Python 2 vs Python 3

过去很多年里,Python存在两个主要版本。从2001年开始,Python 2是标准版本,这意味着大多数关于Python的图书和文章都是为这个版本写的。Python 2的最后一个版本是Python 2.7。

现在的主线版本是Python 3,开发时称为Python 3000或Py3k。从2008年年末发布Python 3到2019年,我们处于Python 2和Python 3两个主要版本之间:许多现有的代码和包都是用Python 2编写的,而Python 3则被越来越多地推荐用于不需要支持Python旧版本的新项目。许多技术和工具都存在兼容Python 2和Python 3的代码,这有助于当时许多项目的过渡。

但最近几年,尤其是Python 3.5发布后,我们开始完全摆脱Python 2。大多数主要的库支持Python 3,而对Python旧版本的支持则变得不那么重要。

2020年1月1日,Python 2正式停止维护,Python 3成为标准版本。Python 4目前仍然只是一个模糊的传闻,所以可以肯定的是,Python 3将会在未来几年一直存在。

遗憾的是,许多软件开发团队将代码从Python 2迁移到Python 3的速度很慢(有时是不可避免的),这使许多项目陷入了困境。如果你在专业领域使用Python,那么你很有可能需要协助将一些代码迁移到Python 3。Python的标准库包含一个名为2to3的工具,它可以帮助你自动化这个过程。将代码通过这个工具运行是很好的第一步,但是你仍然需要手动更新代码以使用Python 3提供的一些新模式和工具。

1.4 定义“Pythonic”代码

作为一个Python开发者,你可能无数次地听到关于Pythonic代码的讨论,究竟什么是Pythonic代码呢?通常来说,能较好利用语言本身功能的惯用代码被认为是Pythonic代码。

遗憾的是,这非常容易被过度演绎。因此,Python中最佳实践的话题在社区中经常引发激烈的争论。不要因此而惊慌。通过经常与我们自己的习惯和标准进行斗争,我们将不断改进它们和我们自己的理解。

我们在Python中讨论最佳实践的倾向源于我们的哲学,即“只有一种方法可以做到这一点”(There’s Only One Way To Do It,TOOWTDI),这句话是PythonLabs在2000年提出的,作为对Perl社区的格言“有多种方法可以做到这一点”(There’s More Than One Way To Do It,TMTOWTDI)的一种讽刺性回应。尽管这些社区之间存在历史性对抗,但这些哲学并不严格相反。

Python开发者们很有理由相信,对于任何特定问题,都有单一的、可量化的“最佳”解决方案。我们的任务是找出这个解决方案,但我们也知道我们往往会远远落后于目标。通过进行持续的讨论、争论和实验,我们不断改进我们的方法,以追求理论上的最佳解决方案。

同样,Perl社区明白很难一次性地给出最佳解决方案,因此他们强调实验而不是遵守严格的标准,以努力发现更好的解决方案。

最终,我们所有人的目标都是一致的:定义出最好的解决方案。只不过我们各自有着不同的重点。

在本书中,我将重点介绍已广泛接受的编写代码的Pythonic方法。但我不认为自己是最终的权威,Python社区的同行们始终有很多东西可以添加到这些讨论中,我将会持续不停地从他们那里学习新的东西!

1.5 Python之禅

1999年,Python官方邮件列表上开始了一场关于编写一些通用化的指导原则的讨论。Tim Peters是社区的一位突出成员,他玩笑式地以类似于诗歌的方式提出了19条原则作为大纲,并留下了第20个位置请Guido van Rossum来完成(但他从未完成过)。

其余的社区成员很快就把这个总结视为对Python哲学的一个很好的概述,最终将其整体作为Python之禅(The Zen of Python)。整个文本则作为PEP 20由Python官方发布。

这些原则如下

优雅好过丑陋。

显式好过隐式。

简单好过复合。

复合好过复杂。

扁平好过嵌套。

稀疏好过密集。

可读性很重要。

即使要为了实用性而牺牲纯粹性,

特例也并不特殊到足以破坏规则。

不应悄悄放过错误,

除非确定需要这样。

面对太多可能,不要尝试猜测。

应该有一种(且最好只有一种)明显的方式来做到这一点。

虽然这并不容易,毕竟你不是那位荷兰人

虽然一直不做总是要好过匆忙去做,

但是现在就做还是要好过永远不做。

若实现方案很难解释,那它肯定不是个好方案;

若实现方案很好解释,那它有可能是个好方案。

命名空间是个绝妙想法——我们应该多使用它!

这些原则是开放的,可以解释为不同的意思,有些人甚至认为Tim Peters在写Python之禅时是在开玩笑。但是在这个过程中,我学到了一个很重要的道理,那就是对Python开发者而言,“开玩笑”和“认真”之间的界限是非常细微的。

在任何情况下,Python之禅都是讨论Python最佳实践的好地方,许多开发者(包括我自己)经常会回到这里。在本书中,我也会经常提到它。

1.6 文档、PEP和你

本书的目的是成为你学习Python的起点,而不是终点。一旦你熟悉了Python,你就可以转到Python官方文档,了解更多关于特定功能或工具的知识。

Python中的任何新功能都是从Python增强提案(Python Enhancement Proposal,PEP)开始的。每个PEP都有唯一的编号,并已发布到官方PEP索引中。一旦提出了PEP,它就会被考虑、讨论,最终被接受或拒绝。

一个PEP被接受后,它就是文档的一部分,因为它们是定义Python功能的最具凝聚力和权威性的描述。此外,还有几个元PEP(Meta-PEP)和信息PEP(Informational PEP),它们为Python社区和语言提供了支撑。

因此,如果你有任何关于Python的问题,官方文档和PEP索引应该是你首先要去的地方。在本书中,我也会经常提到它们。

1.7 社区中谁说了算?

为了理解语言是如何演变的,以及为什么会演变,了解谁在掌控很重要。当一个PEP被提出时,谁来决定它是被接受还是被拒绝?

Python是一个归属于非营利性组织——Python软件基金会的开源项目。与许多其他流行的语言不同,Python和任何营利性组织之间没有正式的关联。

作为一个开源项目,Python受到活跃而充满活力的社区的支持。核心团队由一群维护语言和让社区运行得更加顺畅的可信的志愿者构成。

Python的创造者Guido van Rossum过去是“仁慈的终身独裁者”(Benevolent Dictator for Life,BDFL),他对所有PEP进行最终决策,并监督Python的持续发展。2018年,他决定不再担任这个角色。

在他退休后,PEP 13被创建,以建立新的治理系统。现在,Python语言由核心团队选举出的5人领导小组来管理。每次Python的新版本发布时,都会选出新的领导小组。

1.8 Python社区

Python社区(Python Community)庞大且多样化,由来自世界各地的人构成,他们都因对这种独特的语言的热爱而团结在一起。自从我多年前作为一个完全的新手偶然发现这个社区以来,我从中获得了无法估量的帮助、指导和灵感。我也很荣幸能够为他人提供同样的帮助。如果没有Python社区朋友们的不断反馈,本书就不会面世!

Python社区由核心团队主持,依据Python行为准则来管理。简而言之,Python社区强调开放、体贴和尊重的行为,总结如下。

总的来说,我们彼此尊重。我们之所以为这个社区做出贡献,是因为我们想要做出自己的贡献,而不是有人强迫我们。如果我们记住这一点,这些准则就会自然而然地出现。

我强烈推荐任何使用Python的开发者加入这个活跃的社区。参与其中的最好方法之一是通过Libera在线聊天室的#python频道。你可以在Python官网的Community页面找到进入Libera在线聊天室的指南。

如果你对Python有任何问题(包括在阅读本书时),我建议你到Libera在线聊天室的#python频道寻求帮助。你很有可能在那里遇到我和本书大部分的技术审校团队成员。

在第21章,我将从多个方面讨论Python社区。

1.9 对“明显的方式”的追求

Python的口号“只有一种方式”,一开始可能会让人感到困惑。解决任何一个问题都有很多种可能的方法,Python爱好者们是对自己的想法太着迷了吗?

幸运的是,不是这样的。这个口号意味着更加鼓舞人心的东西,这也是每一个Python开发者都应该理解的。

一些观点来自Python之禅,其中包括如下两个相当神秘的句子。

应该有一种(且最好只有一种)明显的方式来做到这一点。

虽然这并不容易,毕竟你不是那位荷兰人。

Tim Peters当然是在调侃Python的创造者Guido van Rossum——他是荷兰人。作为Python的创造者,Guido可以很容易地找到解决Python问题的“明显的方式”,尤其是在早期。

“明显的方式”(obvious way)是Python的一个术语,用于描述“最佳解决方案”——良好的实践、干净的风格和合理的效率的结合,使得代码即使对于学习Python的新手也是易于理解的。

问题的细节通常会影响这种“明显的方式”:一种情况可能需要循环,另一种可能需要递归,还有一种可能需要列表推导式。与通常意义上的“明显”相反,解决方案通常并不简单。最佳解决方案只有在你知道它之后才会显而易见,而怎么到达这一点是最棘手的。

然而,对“明显的方式”的追求是Python社区的一个定义性特征,它对本书产生了深远的影响。书中的很多见解都是在我和我的Python爱好者同行之间进行的激烈辩论中产生的。因此,我从那些常常与我争论技术细节的同行中挑选出了我的技术审校团队成员,而且他们经常彼此对立。

任何最终被认为是解决问题的“正确方式”的方案通常都是因为其技术优势才被接受的,而不是因为Python开发者之间的一些类似的偏见,这些开发者是我曾经有幸合作的最严格的人。这种逻辑的方法溢出到了我们每一次的对话中(这导致一些非常惊人和具有启发性的学术辩论)。

新的情况会不断出现。在任何Python开发者的职业生涯中,编码永远不会变得真正“简单”。每个项目中都会出现需要仔细考虑的情况,而且通常还会有争论。开发者必须尝试以对他们来说最明显的方式解决问题,然后将解决方案提交给同行进行评审。

在我看来,本书中的方法在很多情况下都是最明显的,大多数得到了我的同行们的支持,但我敢肯定的是,我在Python方面差了Guido van Rossum很多。如果你发现自己在Python社区中争论技术,那么请不要把本书举在任何人的面前,作为你的解决方案最好的证据!找到明显的解决方案的技能是不可教的,只能通过实践来学习。

1.10 本章小结

尽管多年来有许多关于Python的传言,但Python是一种多功能且技术上可靠的语言,几乎可以处理你抛出的任何问题。无论你是编写自动化脚本、处理大型数据集、构建本地用户应用程序、实现机器学习,还是制作Web应用程序和应用程序接口(Application Program Interface,API),Python都是一个可靠的选择。最重要的是,Python有一个活跃、多样化和能提供帮助的社区。

成功的关键是编写Python代码,以充分利用Python的优点和功能。目标不仅仅是编写能工作的代码,而是编写优雅的代码。本书接下来的部分将教你如何做到这一点。 RfjrAlfAyQmSQWLKcg+H1rMjXNZNdyq4JpEXrrv/+Tsh2fqpS4t6fSQlASoPd3Wf

点击中间区域
呼出菜单
上一章
目录
下一章
×

打开