Python编程入门与实战(第3版)

978-7-115-60738-6
作者: [意]法布里奇奥·罗马诺(Fabrizio Romano)[英]海因里希·克鲁格(Heinrich Kruger)
译者: 徐波
编辑: 郭泳泽
分类: Python

图书目录:

详情

本书是一本全面介绍Python编程,并针对多个应用场景给出解决方案的编程手册。从Python的基础知识开始,介绍了数据类型、函数、条件、循环等基本概念,展示了生成器、面向对象编程等具有Python特色的进阶理念,并给出了定位和排除异常、测试代码、调试的方法。随后,本书针对GUI、数据科学等实用场景,使用Python解决实际问题。最后,本书给出了发布Python程序的方法。 本书适合想要学习编程或有一定编程基础、想要学习Python的人阅读。

图书摘要

版权信息

书名:Python编程入门与实战(第3版)

ISBN:978-7-115-60738-6

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。


版  权

著    [意]法布里奇奥·罗马诺(Fabrizio Romano) [英]海因里希·克鲁格(Heinrich Kruger)

译    徐 波

责任编辑 郭泳泽

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315

读者服务:

微信扫码关注【异步社区】微信公众号,回复“e60738”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。

内 容 提 要

本书是一本全面介绍Python编程,并针对多个应用场景给出解决方案的编程手册。本书从Python的基础知识开始,介绍了数据类型、函数、条件、循环等基本概念,展示了生成器、面向对象编程等具有Python特色的高级概念,并给出了定位和排除异常、测试代码、调试的方法。随后,本书针对GUI、数据科学等实用场景,使用Python解决实际问题,最后给出了发布Python程序的方法。本书适合想要学习编程或有一定编程基础、想要学习Python的人阅读。

作者简介

法布里奇奥·罗马诺(Fabrizio Romano),1975年出生于意大利。他获得了帕多瓦大学计算机科学工程硕士学位。他从1999年开始成为一名专业的软件开发人员。法布里奇奥自2016年起成为Sohonet产品团队的成员。2020年,该团队被美国电视学院授予技术及工程艾美奖,以表彰他们在高级远程协作方面的卓越贡献。

“我想感谢Packt出版社的每位工作人员和本书的审核人员,他们对于本书的成功是不可或缺的。我还想感谢海因里希·克鲁格和汤姆·瓦伊纳,感谢他们与我共同经历的这一切。我最感激的是我的未婚妻埃莉萨。感谢你们!感谢你们的关爱和支持。”

海因里希·克鲁格(Heinrich Kruger),1981年出生于南非。他获得了荷兰乌得勒支大学的计算机科学硕士学位。他从2014年开始成为一名专业的软件开发人员,并从2017年开始加入Sohonet产品团队,成为法布里奇奥的同事。

“感谢法布里奇奥邀请我参与本书的编写。能够与你一起工作我深感荣幸。感谢汤姆·瓦伊纳和罗东熙!感谢他们提出的很多宝贵意见。感谢Packt出版社中帮助我们完成本书的所有同仁。最重要的是,我要感谢我的妻子黛比,感谢她对我的爱护、鼓励和支持。”

审校者简介

汤姆·瓦伊纳(Tom Viner)是一位居住在伦敦的卓越软件开发者。他在创建Web应用程序方面有着超过13年的经验,使用Python和Django也已长达10年之久。他对开源软件、Web安全和测试驱动的开发有着非同寻常的兴趣。

“感谢法布里奇奥·罗马诺和海因里希·克鲁格邀请我对本书进行审校。”

罗东熙(Dong-hee Na)是一位软件工程师,是开源软件的积极支持者。他就职于Line公司,担任后端工程师。他在基于Python和C++的机器学习项目中具有丰富的专业经验。在开源项目中,他专注于编译器和解释器领域,尤其是在与Python有关的项目中。他从2020年开始成为一名CPython核心开发人员。

前  言

本书的第1版在我40岁生日的时候问世。它似乎近在眼前,但实际上已经过去了6年。仅用了几周,该书就成为顶级的畅销书。时至今日,我仍然不断地收到来自全世界的问候和邮件。

几年后,我编写了第2版。这一版更加出色,不论是畅销程度还是受欢迎程度都超过了第1版。

现在是第3版问世的时候了,这次不再由我单独为读者讲解,因为我亲爱的朋友和同事海因里希·克鲁格也加入了本书的项目中。

我们一起对本书的结构进行了重新组织,删除了不再适合的内容,并增加了能够最大限度地帮助读者的内容。我们对本书进行了调整,对旧的章节进行修订,并撰写了新的章节。我们确信,读者在阅读每一页的时候都能看到我们做出的贡献和我们精心设计的思路。对此,我们感到非常欣慰。

我一直想和海因里希在一个类似本书这样的项目上合作。从我认识他的第一天起,我就对他敬佩有加。他为本书带来了独特的观点,体现了他作为一名软件开发人员的优秀天赋,而且还提高了我的英语水平!

现在Python已经升级到3.9版本,当然大多数代码在任何较新的Python 3版本中都可以运行。关于并发的难度很大的那一章被删除,介绍Web编程的那一章被介绍API概念的新章节所取代。我们还增加了全新的一章讲解如何对Python应用程序进行打包,我们觉得由它作为本书的最后一章非常合适。

我们相信这一版要明显优于之前的版本,它的内容更加成熟,讲解更为流畅,能够让读者身临其境。

我感到非常欣慰的一件事情是本书的核心思想依旧如故。这并不仅仅是一本讲述Python的书。首先,也是最重要的是,本书是关于编程的。本书的目标是向读者提供尽可能多的信息。有时候限于篇幅,本书会提供一些网站,鼓励读者进行更深入的探索。

本书以恒久长新为目标,它表达概念和信息的方式能够经得起时间的考验。我们投入了大量的时间和精力努力实现这个目标。

读者可以下载本书的代码,我们鼓励读者对代码进行尝试、扩展、更改、破坏,看看会发生什么。我们希望读者能够养成批判性思维,能够独立自主地开展工作。这就是本书的灵魂所在。我们希望在读者进入本书的学习之旅后,它可以尽其所能地帮助读者走得更远,成为更优秀的程序员。

当我们基于第2版的草稿开始撰写第3版时,我非常惊讶地发现无法在这些书页上找到自己的影子。这些书页显示了我的思维方式以及我的写作风格在过去几年里发生了怎样的改变。

变化一直交织在这个世界的每个角落里,所有的东西都在一直发生变化。因此,我们希望读者的思维不要僵化。我们希望自己的工作和讲解方式可以帮助读者保持灵活、聪明、务实,不断地适应新事物。

祝读者好运!不要忘了享受学习的乐趣!

本书的目标人群

本书的读者应该具有一定的编程经验,但并不需要熟悉Python。如果读者掌握一些基本的编程概念,对于阅读本书会有所帮助,但这并非先决条件。

即使读者已经有过一些Python编程的经验,本书仍然能够提供很大的帮助,它不但可以作为Python基础知识的参考书,而且提供了范围极广的思路和建议,这是集两位作者40年的工作经验提炼而成的。

本书涵盖的内容

第1章讲述了基本的编程概念和Python语言的结构。它还指导读者在自己的计算机中安装和运行Python。

第2章讲述了Python的内置数据类型。Python提供了丰富的本地数据类型,本章提供了每种数据类型的描述和示例。

第3章讲述了如何插入条件、应用逻辑、执行循环以控制代码的执行流。

第4章讲述了如何编写函数。函数对于代码的复用、减少调试时间、编写质量更高的代码至关重要。

第5章讲述了Python编程的功能特点。本章指导读者编写解析和生成器,它们是功能极为强大的工具,可用于编写更加快速、更加简洁的代码,并且能够节省内存。

第6章讲述了用Python进行面向对象编程的基础知识。本章介绍了这种编程模式的关键概念和所有潜在特点。本章还讲述了Python语言实用的特性之一:装饰器。

第7章介绍了异常的概念,它表示应用程序中出现的错误。本章讲述了如何处理异常,并且还介绍了上下文管理器,后者在处理资源时非常实用。

第8章讲述了如何处理文件、流、数据交换格式、数据库。

第9章讲述了安全、散列、加密、令牌的概念,它们是编写安全软件的关键所在。

第10章讲述了测试的基础知识,并指导读者通过一些示例掌握如何对代码进行测试,使代码更加健壮、快速、可靠。

第11章讲述了对代码进行调试和性能分析的主要方法,并提供了如何应用这些方法的一些示例。

第12章从两个不同的角度完成一个示例:一种实现是脚本,另一种实现是图形用户界面(GUI)应用程序。

第13章通过一个综合性的例子,使用功能强大的Jupyter Notebook,描述了一些关键的概念。

第14章介绍了API开发和Python的类型提示,还提供了关于如何消费API的不同例子。

第15章指导读者完成一个项目的发布准备过程,并讲述了如何把打包结果上传到Python包索引(PyPI)。

最大限度地利用本书

我们鼓励读者对本书的所有示例进行试验。读者需要计算机、网络连接和浏览器。本书是为 Python 3.9 编写的,但也适用于 Python 3 的所有较新版本。我们提供了在操作系统中安装Python的指南。具体的做法很快就会过时,因此我们推荐读者在网络上寻找最精确的安装指南。我们还解释了如何安装本书各章使用的所有额外程序库。在输入代码时,本书并没有要求使用任何特定的编辑器,但我们建议读者如果想运行全书的代码,可以考虑使用一种合适的编码环境。我们在本书的第1章提供了这方面的一些建议。

下载示例代码文件

本书的代码包可以从GitHub网站的PacktPublishing/Learn-Python-Programming-Third-Edition资源库中获取。读者还可以从GitHub网站的PacktPublishing主页所提供的丰富图书和视频目录中获取其他代码包。

下载彩色图像

我们还提供了一个PDF文件,其中包含了本书使用的截图或示意图的彩色图像。读者可以通过本书的配套资源获取这个文件。

本书使用的约定

下面是本书使用的一些文本约定。

本书的代码段按照下面的方式设置:

# 我们定义一个名为local的函数
def local():
    m = 7
    print(m)

当我们希望把读者的注意力集中在代码段的一个特定部分时,相关的代码行或代码项设置为粗体:

# key.points.mutable.assignment.py
x = [1, 2, 3]
def func(x):
    x[1] = 42   # 对原来的实际参数进行了修改!
    x = 'something else' # 使x指向新的字符串对象

所有的命令行输入或输出以下面的形式显示:

>>> import sys
>>> print(sys.version)

黑体:表示新术语、重要词语或屏幕(例如菜单或对话框)上看到的词语。例如,“当一个错误是在执行时被检测到时,它称为异常”。

警告或重要说明以这种形式显示。

提示和技巧以这种形式显示。

资源与支持

本书由异步社区出品,社区(https://www.epubit.com)为您提供相关资源和后续服务。

您还可以扫码右侧二维码, 关注【异步社区】微信公众号,回复“e60738”直接获取,同时可以获得异步社区15天VIP会员卡,近千本电子书免费畅读。

配套资源

本书提供配套代码。

请在异步社区本书页面中点击,跳转到下载界面,按提示进行操作。注意:为保证购书读者的权益,该操作会给出相关提示,要求输入提取码进行验证。

提交勘误

作者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。

当您发现错误时,请登录异步社区,按书名搜索,进入本书页面,单击“提交勘误”,输入勘误信息,单击“提交”按钮即可。本书的作者和编辑会对您提交的勘误进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。

与我们联系

我们的联系邮箱是contact@epubit.com.cn。

如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。

如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区在线投稿(直接访问www.epubit. com/contribute即可)。

如果您所在的学校、培训机构或企业想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。

如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接发邮件给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。

关于异步社区和异步图书

“异步社区”是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网。

“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社近30年的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的LOGO。异步图书的出版领域包括软件开发、大数据、AI、测试、前端、网络技术等。

异步社区

微信服务号

第1章 Python概述

“授人以鱼不如授之以渔。”

——中国谚语

根据维基百科的定义,计算机编程的含义是:

“……设计和生成一个可执行计算机程序的过程,以实现一个特定的计算结果或执行一项特定的任务。编程所涉及的任务包括:分析和生成算法、监测算法的正确性和资源消耗情况、选择使用一种编程语言实现算法(此过程一般称为编码)。”

概括地说,计算机编程就是指示计算机用一种它能理解的语言完成某个任务。

计算机是一种功能非常强大的工具,但遗憾的是,它本身并不具备思考能力。我们需要向它们指定所有的任务细节:怎样执行一个任务、怎样评估一个条件以决定采取哪条路径、怎样处理来自某个设备(例如网络或磁盘)的数据以及当某件不可预见的事情(例如什么东西坏了或者不见了)发生时应该采取什么操作。

我们在编写代码时可以选择许多不同的风格和语言。编程是不是很难?可以说是,也可以说不是。它有点像写作,这是每个人都可以学会的技能。但是,如果我们想成为一名诗人呢?要想成为诗人,光知道怎样写作是远远不够的。我们还需要掌握一整套的其他技巧,而这需要大量的时间和精力。

最后,编程还取决于我们想要在这条道路上走得多远。编程绝不仅仅是把一些指令组合在一起使之能够运行,它意味着更多事情!

优秀的代码短小、快速、优雅、易于阅读和理解、简单、易于修改和扩展、易于缩放和重构,并且容易进行测试。想要编写同时具备上述特点的代码需要时间的积累,不过有个好消息是当读者阅读本书的时候,就已经朝着这个目标迈出了可喜的第一步。我们毫不怀疑读者能够做到这一点。事实上,每个人随时都在进行着编程,只不过他们并没有意识到这一点。观察下面的例子。

假设我们想泡一杯速溶咖啡。我们必须要有咖啡杯、速溶咖啡罐、茶匙、水、水壶。即使我们并没有意识到,实际上已经对大量的数据进行了评估。我们需要确保水壶中有水并且水壶已经插上了电、咖啡杯必须已经洗干净了并且咖啡罐里有足够的咖啡。然后,我们烧好开水,同时在咖啡杯里倒入一些咖啡。水烧开之后,就可以把开水倒入杯中并进行搅拌。

那么,这个过程中的编程体现在什么地方呢?

没错,我们收集资源(水壶、咖啡、水、茶匙、咖啡杯)并验证一些与它们有关的条件(水壶已经插上电、咖啡杯已经洗干净、咖啡的数量足够)。然后我们开始两项活动(烧开水、把咖啡倒入咖啡杯中),当这两项都完成之后,我们把开水倒入咖啡杯中并进行搅拌,从而完成了整个过程。

能不能理解?我们只是在较高的层次上描述了泡咖啡程序的功能。这并不是很难,因为这正是我们的大脑每天所做的事情:评估条件、决定采取操作、执行任务、重复其中一些任务并在某个时刻停止。

现在,我们需要的就是学习如何把自己在现实生活中自动完成的那些活动进行结构分解,使计算机能够实际理解它们。另外,我们还需要学习一种能够指示计算机执行任务的语言。

这就是本书的目的所在。我们将告诉读者一种成功编写代码的方式,并通过许多简单但目标明确的示例来实现这一点。

在本章中,我们将讲解下面这些内容。

Python的特征及其生态系统。

关于安装和运行Python与虚拟环境的指南。

如何运行Python程序。

Python代码的组织形式和Python的执行模型。

1.1 编程预备知识

我们在讲解编程的时候喜欢引用现实世界的例子。我们相信它们可以帮助人们更好地理解相关的概念。但是,现在我们需要采取更严格的方式,更多地从技术的角度观察什么是编程。

当我们编写代码时,我们指示计算机完成一些必须完成的事情。这些活动是在哪里发生的?在许多地方都有可能:计算机内存、硬盘、网线、CPU等。这是一个完整的世界,在大多数情况下可以看成是现实世界的一个子集。

如果我们编写一个软件,允许人们在线购买服装,就必须在程序的边界之内表示现实的人、现实的衣服、现实的品牌、尺码等概念。

为此,我们需要在自己所编写的程序中创建和处理对象。一个人是一个对象,一辆汽车也是一个对象,一条裤子也是一个对象。幸运的是,Python能够很好地理解对象这个概念。

任何对象都有两个主要特性:属性方法。我们以人这个对象为例。一般情况下,在计算机程序中,人这个对象是以顾客或员工的形式出现的。我们在这种对象中所存储的属性包括姓名、社会保障号码、年龄、是否拥有驾照、电子邮件、性别等。在计算机程序中,我们存储所有必要的数据,以便按照预期的方式使用这种对象。如果我们为一个销售服装的网站编写代码,除了顾客的其他信息之外,很可能还需要存储身高和体重数据,以便向他们推荐合适的服装尺码。因此,属性就是对象的特征。我们实际上一直在使用对象的属性:“可以把那支笔递给我吗?”“哪一支?”“黑色的那支”。在这里,我们使用了笔的颜色(黑色)属性来标识这个对象(它很可能和其他不同颜色的笔放在一起,必要时通过颜色进行区分)。

方法就是对象可以做的事情。作为一个人,我可以说话、走路、睡觉、醒来、吃东西、做梦、写字、阅读等。我可以做的任何事情都可以看成是表示我的那个对象的方法。

现在,我们知道了什么是对象,并且知道了它们提供了一些可以运行的方法和一些可以检查的属性,这样我们就可以开始编写代码了。编写代码实际上就是简单地对我们的软件所复刻的世界子集中所存在的对象进行管理。我们可以按照自己的意愿创建、使用、复用、删除对象。

根据Python官方文档的“数据模型”这一章的说法:

“对象是Python对数据的抽象。Python程序中的所有数据都是由对象或者对象之间的关系所表示的。”

我们将在第6章中更深入地讨论Python对象。现在,我们只需要知道Python中的每个对象都有ID(或称为标识)、类型、值

一旦创建了一个对象之后,它的ID就不会改变。每个ID都是一个独一无二的标识符,当我们需要使用这个对象时,Python就会在幕后用ID来提取这个对象。同样,对象的类型也不会改变。类型决定了对象所支持的操作以及可以向对象赋什么样的值。我们将在第2章中讨论Python的大部分重要数据类型。对象的值有些能够改变,有些不能改变。如果可以改变,这种对象就称为可变(mutable)对象。如果不能改变,这种对象就称为不可变(immutable)对象。

我们应该怎样使用对象呢?当然,我们需要为它提供一个名称!当我们为一个对象提供一个名称后,就可以用这个名称提取这个对象并使用它。从更基本的意义上说,像数值、字符串(文本)、集合这样的对象是与一个名称相关联的。我们通常把这种名称叫作变量名。我们可以把变量看成可以保存数据的盒子。

现在,有了需要的所有对象之后,接下来应该怎么做呢?不错,我们需要使用它们。我们可能需要通过网络连接发送它们或者把它们存储在数据库中。我们也可能想把它们显示在一个网页上或者把它们写入一个文件中。为此,我们需要对用户填写表单或者点击按钮或者打开网页并进行搜索的行为做出响应。我们通过运行自己的代码对这些行为做出响应,对条件进行评估以选择需要执行的程序部分、确定需要执行多少次以及需要在什么样的情况下执行。

为了实现这个目的,我们需要一种语言,Python就适合这种用途。Python是我们在本书中指示计算机执行任务时所使用的语言。

现在,我们已经介绍了足够的理论背景,可以进入正式的学习之旅了!

1.2 走近Python

Python是荷兰计算机科学家、数学家吉多·范罗苏姆(Guido Van Rossum)的杰出作品,这是他在1989年圣诞节期间参与一个项目时为全世界送上的一份礼物。Python在1991年前后出现在公众视野中,在此之后不断发展,逐渐成为当今世界广泛使用的主流编程语言之一。

我们都从很小的时候就开始学习编程。法布里奇奥从7岁开始在一台Commodore VIC-20计算机上学习编程,这台机器后来被它的进化版本Commodore 64所取代。它所使用的语言是BASIC。海因里希是从高中学习Pascal的时候开始学习编程的。我们用Pascal、汇编语言、C、C++、Java、JavaScript、Visual Basic、PHP、ASP、ASP.NET、C#以及其他很多我们甚至已经想不起名字的非主流语言编写过程序。但是,直到接触Python之后,我们才最终意识到它才是最适合我们的语言。我们全身心地发出这样的呐喊:“就是它了!这才是最完美的语言!”。

我们只花了一天的时间就适应了它。它的语法与我们所习惯的语法稍有差异,但在克服了最初的不适应(就像刚刚穿上新鞋时)之后,我们都发现自己深深地喜欢上了它。下面我们详细解释为什么Python是一种完美的语言。

1.3 关于Python

在讨论冰冷的细节之前,我们首先要体会为什么需要使用Python(推荐读者阅读维基百科的Python页面,了解更详细的信息)。

对我们而言,Python具有下面这些优点。

1.3.1 可移植性

Python可运行于范围很广的平台,把一个程序从Linux移植到Windows或Mac通常只需要修改路径和设置就可以了。Python在设计时充分考虑了可移植性,能够处理特定操作系统(OS)接口背后的古怪特性,从而避免了在编写代码时不得不进行剪裁以适应某个特定平台的麻烦。

1.3.2 一致性

Python具有极强的逻辑性和一致性。我们可以看到它是由一位卓越的计算机科学家所设计的。大多数情况下,即使我们并不熟悉某个方法,也可以猜出它是怎么被调用的。

现在,读者可能还没有意识到这个特点的重要性,尤其在初学编程的时候。但是,这是Python的一个主要特性。它意味着我们的大脑中不会有太多混乱的东西,并且需要阅读的文档也很少,当我们编写代码时需要理解的映射关系也很少。

1.3.3 开发人员的效率

根据Mark Lutz(Learning Python第5版,O’Reilly Media)的说法,Python程序的长度一般只有对应的Java或C++程序的五分之一到三分之一。这意味着使用Python可以更快速地完成工作。快速显然是个很好的优点,意味着在市场上能够得到更快的响应。更少的代码不仅意味着需要编写的代码更少,同时意味着需要阅读(专业程序员所阅读的代码数量要远远多于他们所编写的代码)、维护、调试、重构的代码也更少。

Python的另一个重要优点是它在运行时不需要冗长耗时的编译和链接步骤,因此我们不需要等待就可以看到自己的工作成果。

1.3.4 广泛的程序库

Python提供了一个标准库(就像手机的随机电池),其涵盖范围之广令人难以置信。如果觉得这还不够,遍布全球的Python社区还维护了一个第三方的程序库主体,可以通过裁剪适应具体的需要。我们可以很方便地通过Python包索引(PyPI)获取它们。在大多数情况下,当我们编写Python代码并感觉需要某个功能时,至少有一个程序库已经实现了这个功能。

1.3.5 软件质量

Python专注于可读性、一致性和质量。语言的一致性提供了极高的可读性,这在如今是至关重要的,因为现在的代码往往是多人合作的成果,而不是一个人的单独工作。Python的另一个重要特点是它内在的多范式性质。我们可以把它当作一种脚本语言,但是也可以采用面向对象式的、命令式的和函数式的编程风格。它是一种极为全能的语言。

1.3.6 软件集成

Python的另一个重要特点是它可以扩展并与其他许多语言进行集成,这意味着即使一家公司使用另一种不同的语言作为主流工具,仍然可以使用Python作为复杂应用程序之间的黏合剂,使它们可以按照某种方式彼此通信。这个话题比较高级,但是在现实世界中,这个特性是非常重要的。

1.3.7 满足感和乐趣

最后一个但绝非不重要的特点是它的乐趣!用Python编写代码是一件快乐的事情。我们可以编写8个小时的代码,然后兴高采烈并心满意足地离开办公室。其他程序员就没这么惬意了,因为他们所使用的语言并没有提供同等数量的设计良好的数据结构和代码结构。Python使编程充满乐趣,这点是毫无疑问的。编程的乐趣能够提升工作动力和工作效率。

上面这些优点是我们向每个人推荐Python的主要原因。当然,我们还可以举出其他许多技术特点和高级特性,但在入门章节中并不适合讨论这些话题。它们将会在本书后面详细讲解Python时自然而然地呈现在读者面前。

1.4 Python的缺点

我们在Python中唯一可以找到的与个人偏好无关的缺点就是它的执行速度。一般而言,Python代码的执行速度要慢于经过编译的代码。Python的标准实现在我们运行程序时会生成源代码的编译版本,称为字节码(扩展名为.pyc),然后由Python解释器运行。这种方法的优点是可移植性高,其代价是速度较慢,因为Python不像其他语言一样编译到机器层次。

尽管如此,Python的运行速度在当今这个时代并不是什么问题,因此这个并不重要的缺点并没有影响它的广泛应用。在现实生活中,硬件成本不再是什么问题,并且通过任务的并行化很容易实现速度的提升。而且,许多程序的大部分运行时间花在等待I/O操作的完成上。因此,原始运行速度只是总体性能的一个次要因素。

在速度确实非常重要的场合,我们可以切换为更快速的Python实现,例如PyPy,它通过一些高级的编译技巧,平均能够提升4倍的速度。我们也可以用速度更快的语言(例如C或C++)编写代码中性能关键的部分,并将它们与Python代码集成。像pandasNumPy这样的程序库(常用于在Python中实现数据科学的操作)就使用了这样的技巧。

Python语言有一些不同的实现。在本书中,我们将使用引用实现,称为CPython。读者可以从Python官网找到其他实现的列表。

如果觉得说服力还不够,可以注意到Python已经用于驱动像Spotify和Instagram这样非常重视性能的后端服务。从这一点看,可以认为Python能够完美地完成各种任务。

1.5 当前的Python用户

仍然没有被说服?我们简单地观察一下当前使用Python的公司:Google、YouTube、 Dropbox、Zope Corporation、Industrial Light & Magic、Walt Disney Feature Animation、Blender 3D、Pixar、NASA、the NSA、Red Hat、Nokia、IBM、Netflix、Yelp、Intel、Cisco、HP、Qualcomm、JPMorgan Chase和Spotify,这些仅仅是其中的一部分。甚至像Battlefield 2Civilization The Sims 4这样的游戏也是用Python实现的。

Python可用于许多不同的环境,例如系统编程、网页和API编程、GUI应用程序、游戏和机器人、快速原型、系统集成、数据科学、数据库应用、实时通信等。一些声名卓著的大学已经采用Python作为计算机科学课程的主要教学语言。

1.6 安装环境

在讨论如何在系统中安装Python之前,我们首先说明本书所使用的Python版本。

Python 2和Python 3

Python有两个主要版本:旧版本Python 2和现在的新版本Python 3。这两个版本尽管非常相似,但是有几个方面是不兼容的。

在现实世界中,Python 2现在只用于运行遗留软件。Python 3早在2008年就出现了,从Python 2到Python 3的漫长转换差不多已经结束了。Python 2在业界被广泛使用,因此为了完成转换,往往需要漫长的时间和巨大的精力。有些Python 2软件一直没有被更新为Python 3,只是因为并不值得为此付出太多的时间和精力。因此,有些公司仍然和原先一样保留了旧的遗留系统,而不是为了更新而更新。

在本书写作之时,Python 2已经不被提倡,大多数广泛使用的程序库已经移植到了Python 3。如果需要开启一个新项目,强烈建议使用Python 3。

在过渡阶段,许多程序库进行了重写,以便与两个版本都兼容,这主要是利用了six程序库的功能(这个名称来自2×3,表示从版本2到版本3的移植),它可以帮助我们根据所使用的版本对程序库的行为进行自查和变更。现在,Python 2已经到达了它的生命终点(End of Life,EOL),有些程序库开始改变态度,不再支持Python 2。

根据PEP 373(参见Python官方文档),Python 2.7的生命终点被设置为2020年。Python 2的最后版本是2.7.18,不存在Python 2.8。

在法布里奇奥的计算机(MacBook Pro)上,使用的是最新版本的Python:

>>> import sys
>>> print(sys.version)
3.9.2 (default, Mar 1 2021, 23:29:21)
[Clang 12.0.0 (clang-1200.0.32.29)]

因此,我们可以看到版本是Python 3.9.2,该版本是在2021年3月1日发布的。上面的文本与我们在控制台所输入的Python代码有点相似。稍后我们将对此进行讨论。

本书的所有例子都是用Python 3.9运行的。如果读者想要运行本书的所有例子并下载本书的所有源代码,请确保使用的是同样的Python版本。

1.7 安装Python

我们并没有想到要在本书中专门安排一个“安装”章节,尽管读者确实需要安装一些东西。大多数情况下,作者编写书中的代码与读者实际运行这些代码之间存在几个月的时间差。过了这么长时间,很可能已经发生了版本的变化,本书所描述的方法很可能已经不再适用。幸运的是,我们现在有了网络。因此,为了帮助读者完成安装和运行,我们将提供一些指南和目标。

我们注意到本书的大多数读者希望书中能够提供一些关于安装Python的指导。我们并不认为这能够为读者提供真正的帮助。我们非常坚定地认为,如果读者想要学习使用Python进行编程,一开始花点时间熟悉它的生态系统是极有帮助的。这是非常重要的,当读者阅读以后的章节时会极大地提升信心。如果在这个过程中遇到困难,记住搜索引擎是我们的好朋友。在安装过程中,所有相关的问题都可以在网络上找到。

1.7.1 安装Python解释器

我们首先讨论操作系统。Python是完全集成的,并很可能已经安装于几乎每个Linux系统中。如果读者使用的计算机系统是macOS,很可能也已经安装了Python(尽管很可能只支持Python 2.7)。但是,如果读者使用的是Windows,很可能需要自己安装Python。

获取Python和必要的程序库并使之能够运行,需要一些手工活。对于Python程序员而言,Linux和macOS是相当友好的操作系统。反之,使用Windows系统的程序员就需要付出一些额外的精力。

读者首先需要关注的是Python的官方网站。这个网站提供了Python的官方文档和其他很多非常实用的资源。读者应该花点时间探索这个网站。

另一个提供了 Python 及其生态系统的丰富资源的优秀网站是The Hitchhiker’s Guide to Python。读者可以在这个网站中找到在不同的操作系统中安装Python的不同方法。

在这个网站中找到安装部分,并选择适合自己的操作系统的安装程序。如果操作系统是Windows,要确保在运行安装程序时检查安装pip选项(实际上,我们建议进行完整的安装,为了安全起见,最好安装所有的组件)。如果读者需要在 Windows 上安装Python的更多指南,可以参考 Python 官方文档。

在操作系统中安装了Python之后,接下来的目标就是打开控制台窗口并输入python,运行Python交互式shell

注意,我们通常简单地用Python控制台表示Python交互式shell。

为了在Windows中打开控制台,进入“开始”菜单,选择“运行”并输入cmd。如果在运行本书的示例时遇到类似权限这样的问题,请确保以管理员身份运行控制台。

在macOS中,可以通过“应用程序”>“工具”>“终端”启动一个终端窗口。

使用Linux操作系统的读者很可能已经知道关于控件台的所有信息。

我们将使用控制台这个术语表示Linux的控制台、Windows的命令行窗口和Macintosh的终端。我们还将用Linux默认格式表示命令行的输入提示,如下所示:

$ sudo apt-get update

如果读者对此并不熟悉,可以花些时间学习控制台工作方式的基础知识。概括地说,在$符号之后,一般是一条必须输入的指令。注意大小写和空格,它们是非常重要的。

不管打开的是哪种控制台,在提示符后面输入python,确保显示Python交互式shell。输入exit()退出控制台窗口。记住,如果操作系统预安装了Python 2,可能需要指定Python 3。

下面大概就是读者在运行Python时所看到的(根据版本和操作系统,细节可能有所不同):

fab $ python3
Python 3.9.2 (default, Mar 1 2021, 23:29:21)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

既然已经安装了Python并可以运行,现在需要确保运行本书的示例所需的另一个工具(即虚拟环境)也就绪。

1.7.2 关于虚拟环境

用Python进行工作时,使用虚拟环境是极为常见的。我们将解释什么是虚拟环境,并通过一个简单的示例说明为什么需要虚拟环境。

我们在系统中安装Python,并为顾客X做一些网站相关的工作——项目X。我们创建一个项目文件夹并开始编写代码。在这个过程中,我们还安装了一些程序库,例如Django框架。我们将在第14章介绍这个程序库。我们假设为项目X所安装的Django版本是2.2。

现在,网站运作良好,因此我们又迎来了另一位顾客Y。她要求我们创建另一个网站,因此我们启动了项目Y,并且在这个过程中需要再次安装Django。唯一的问题是,现在Django的版本是3.0,我们无法把它安装在自己的系统中,因为这将替换我们为项目X所安装的版本。我们不想冒引入不兼容问题的风险,因此我们面临两个选择:要么继续沿用自己的计算机当前所安装的版本,要么对它进行更新并确保第一个项目在新版本中仍然能够正确地运行。

坦率地说,这两个方案都不是很有吸引力。因此,我们可以采用另一个解决方案:虚拟环境!

虚拟环境是一种隔离的Python环境,每个虚拟环境都是一个文件夹,包含了所有必要的可执行文件,以便使用Python项目所需要的程序包(暂时可以把程序包看成是程序库)。

因此,我们为项目X创建一个虚拟环境,安装所有的依赖关系,然后可以毫不担心地为项目Y创建另一个虚拟环境并安装它的所有依赖关系,因为我们所安装的每个程序库都被限定在适当的虚拟环境的边界之内。在我们的例子中,项目X将使用Django 2.2,而项目Y将使用Django 3.0。

至关重要的是,我们绝不会在系统层次上直接安装程序库。例如,Linux依赖Python完成许多不同的任务和操作,如果我们变动Python的系统安装,很可能会破坏整体系统的完整性。因此,我们需要制订一个规则,就像在睡觉之前必须刷牙一样:当我们启动一个新项目时,总是为它创建一个虚拟环境。

为了在系统中安装一个虚拟环境,可以采用一些不同的方法。在Python 3.5中,推荐的方式是使用venv模块创建虚拟环境。关于这方面的详细信息,可以参考官方文档。

例如,如果读者使用的是基于Debain的Linux版本,就需要安装venv模块才能使用它:

$ sudo apt-get install python3.9-venv

创建虚拟环境的另一种常见方式是使用Python的第三方程序包virtualenv,详见它的官方网站。

在本书中,我们将使用推荐的技巧,也就是使用Python标准库的venv模块。

1.7.3 第一个虚拟环境

创建虚拟环境是非常简单的。但是,根据系统的配置以及在虚拟环境中需要运行的Python版本,我们需要正确地运行命令。我们使用虚拟环境时需要做的另一件事情就是将其激活。激活虚拟环境相当于在幕后生成一些路径,这样当我们从shell调用Python解释器时,实际上所调用的是那个活动的虚拟环境,而不是系统环境。下面我们展示一个适用于Windows和Ubuntu(在macOS中,过程与Ubuntu非常相似)的完整例子。我们将执行下面的操作。

(1)打开一个终端,进入作为项目根(root)目录的文件夹(此文件夹是srv)。我们将创建一个称为myproject的新文件夹并进入它。

(2)创建一个称为lpp3ed的虚拟环境。

(3)在创建了虚拟环境之后,我们将其激活。Linux、macOS和Windows所采用的方法稍有不同。

(4)运行Python交互式shell,确保当前运行的是我们所需要的Python版本(3.9.X)。

(5)取消虚拟环境的激活。

有些开发人员喜欢用相同的名称称呼所有的虚拟环境(例如.venv)。按照这种方式,他们只需要知道其所关注的项目名称就可以为任何虚拟环境配置工具和运行脚本。.venv中的点号是存在的,因为在Linux/macOS中,在一个名称前加上一个点号可以使该文件或文件夹不可见。

这些步骤就是我们启动一个项目时需要的所有操作。

下面是Windows上的一个例子(注意,根据操作系统、Python版本等的不同,结果可能会有细微的差别)。在下面的指令清单中,以#开始的指令行是注释,为了便于阅读加上了空格,→表示上一行的空间不足导致的换行:

C:\Users\Fab\srv>mkdir my-project # 步骤 1
C:\Users\Fab\srv>cd my-project
 
C:\Users\Fab\srv\my-project>where python # 查找系统中的Python
C:\Users\Fab\AppData\Local\Programs\Python\Python39\python.exe
C:\Users\Fab\AppData\Local\Microsoft\WindowsApps\python.exe
 
C:\Users\Fab\srv\my-project>python -m venv lpp3ed # 步骤 2
 
C:\Users\Fab\srv\my-project>lpp3ed\Scripts\activate # 步骤 3
 
# check python again, now virtual env python is listed first
(lpp3ed) C:\Users\Fab\srv\my-project>where python
C:\Users\Fab\srv\my-project\lpp3ed\Scripts\python.exe
C:\Users\Fab\AppData\Local\Programs\Python\Python39\python.exe
C:\Users\Fab\AppData\Local\Microsoft\WindowsApps\python.exe
 
(lpp3ed) C:\Users\Fab\srv\my-project>python # 步骤 4
Python 3.9.2 (tags/v3.9.2:1a79785, Feb 19 2021, 13:44:55)
→ [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
 
(lpp3ed) C:\Users\Fab\srv\my-project>deactivate # 步骤 5
C:\Users\Fab\srv\my-project>

每个步骤都用一条注释进行说明,因此读者应该能够很顺利地完成这些步骤。

在Linux计算机上,步骤是相同的,但指令稍有区别。而且,我们可能还需要执行一些额外的步骤才能使用venv模块创建虚拟环境。我们无法提供适用于所有Linux版本的指令,因此读者可以在线查找适合自己版本的安装指南。

一旦完成了安装,就可以使用下面的指令创建虚拟环境:

fab@fvm:~/srv$ mkdir my-project # 步骤 1
fab@fvm:~/srv$ cd my-project
 
fab@fvm:~/srv/my-project$ which python3.9 # 查找系统中的Python 3.9
/usr/bin/python3.9 # <-- 系统中的Python 3.9
 
fab@fvm:~/srv/my-project$ python3.9 -m venv lpp3ed # 步骤 2
fab@fvm:~/srv/my-project$ source ./lpp3ed/bin/activate # 步骤 3
 
# 在虚拟环境中再次查找
(lpp3ed) fab@fvm:~/srv/my-project$ which python
/home/fab/srv/my-project/lpp3ed/bin/python
 
(lpp3ed) fab@fvm:~/srv/my-project$ python # 步骤 4
Python 3.9.2 (default, Feb 20 2021, 20:56:08)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
 
(lpp3ed) fab@fvm:~/srv/my-project$ deactivate # 步骤 5
fab@fvm:~/srv/my-project$

注意,为了激活虚拟环境,我们需要运行lpp3ed/bin/activate脚本,后者又需要通过source指令导入当前环境中。当一个脚本进行了source处理之后,意味着它可以在当前的shell中执行,因此它的效果在执行之后仍然会持续。这是非常重要的。另外,注意在激活虚拟环境之后命令提示符所发生的变化,它在左边显示了虚拟环境的名称(当我们取消虚拟环境的激活之后,这个名称就会消失)。

现在,我们应该能够创建并激活一个虚拟环境。读者可以尝试在没有指导的情况下自己创建另一个虚拟环境。读者需要熟悉这个过程,因为这是我们一直在做的事情:我们绝不会用Python进行整个系统的操作,牢记这一点。虚拟环境是极其重要的。

本书的源代码在每一章都有一个专用的文件夹。当某章所显示的代码需要安装第三方程序库时,我们就会包含一个requirements.txt文件(或等价的requirements文件夹,里面有多个文本文件),读者可以据此安装运行代码所需要的程序库。我们建议当读者运行某一章的代码时,为该章创建一个专门的虚拟环境。通过这种方式,读者将会熟悉虚拟环境的创建,并熟悉第三方程序库的安装。

1.7.4 安装第三方程序库

为了安装第三方程序库,需要使用Python Package Installer,称为pip。读者的虚拟环境中可能已经包含了所需的程序库。若是没有,可以通过pip的官方页面了解详情。

下面这个例子说明了如何创建一个虚拟环境,并安装需求文件所要求的一些第三方程序库。

mpro:srv fab$ mkdir my-project
mpro:srv fab$ cd my-project/
 
mpro:my-project fab$ python3.9 -m venv lpp3ed
mpro:my-project fab$ source ./lpp3ed/bin/activate
 
(lpp3ed) mpro:my-project fab$ cat requirements.txt
Django==3.1.7
requests==2.25.1
 
# 使用pip安装所需程序库
(lpp3ed) mpro:my-project fab$ pip install -r requirements.txt
Collecting Django==3.1.7
 Using cached Django-3.1.7-py3-none-any.whl (7.8 MB)
 
... much more collection here ...
 
Collecting requests==2.25.1
 Using cached requests-2.25.1-py2.py3-none-any.whl (61 kB)
 
Installing collected packages: ..., Django, requests, ...
Successfully installed Django-3.1.7 ... requests-2.25.1 ...
 
(lpp3ed) mpro:my-project fab$

在上面这个清单的底部可以看到,pip已经安装了需求文件所指定的两个程序库,并安装了一些其他程序库。这是因为django和requests都有自己所依赖的第三方程序库列表,因此pip会自动安装它们。

因此,做好了相关的准备工作之后,我们可以更多地介绍Python以及它的用法。不过在此之前,我们先简单地讨论一下控制台。

1.7.5 控制台是我们的好帮手

在GUI和触摸屏的时代,在所有的操作都可以通过点击或触碰完成的时候,使用一个像控制台这样的工具听上去有些荒谬。

但事实是,每次我们把自己的右手(如果是左撇子,则是左手)从键盘移开并抓住鼠标,把光标移动到自己想要点击的位置,我们都会浪费一些时间。用控制台完成相同的操作,虽然看上去不太直观,但是它的效率更高、速度更快。作为程序员,我们必须要坚信这一点。

速度和效率是非常重要的。我们并不反对使用鼠标,但另外还有一个非常重要的原因需要我们熟悉控制台操作:当我们开发在服务器上运行的代码时,控制台可能是唯一可用的工具。如果我们熟练掌握了控制台的操作,在紧急状况下就不会陷入手足无措的困境(一个典型的紧急状况是,当网站崩溃,我们必须快速找出原因时)。

如果你还没有做出决定,请相信我们的建议并进行尝试。它比你想象的要容易得多,你绝不会后悔的。对于优秀的开发人员而言,没有什么事情比迷失于一个与某台服务器的SSH连接更为痛心的了,因为他们已经习惯了自己的工具集,而且只熟悉这些工具。

现在,让我们回到Python本身。

1.8 怎样运行Python程序

我们可以使用一些不同的方法运行Python程序。

1.8.1 运行Python脚本

Python可以作为脚本语言使用。事实上,它一直证明了自己是一种非常实用的脚本语言。脚本一般是在完成某个任务时所执行的文件(通常较小)。许多开发人员随着时间的积累会创建他们自己的工具集,并在需要执行一个任务时使用它们。例如,我们可以使用脚本解析某种格式的数据,并把它保存为另一种不同的格式。或者我们可以使用脚本对文件和文件夹进行操作。我们也可以用脚本创建或修改配置文件。从技术上说,没有什么是脚本不能完成的。

让脚本在一台服务器上在某个精确的时间运行是相当常见的做法。例如,如果我们的网站数据库需要每隔24小时清理一次(例如,存储了用户会话的表,它们很快就会过期,但并不会被自动清理),那么我们可以设置一个Cron作业在每天的凌晨3点触发脚本的运行。

根据维基百科的说法,软件工具Cron是一种在类UNIX的计算机操作系统中所运行的基于时间的作业调度工具。人们在设置和维护软件环境时使用Cron(或类似的技术)对作业(指令或shell脚本)进行调度,使其在某个固定的时间、日期或间隔定期运行。

我们用Python脚本完成需要几分钟甚至更多的时间才能手工完成的所有杂务。从某一时刻起,我们决定采用自动化。第12章有一半的篇幅介绍使用Python编写脚本。

1.8.2 在交互式shell中运行Python

运行Python的另一种方法是调用交互式shell。这正是此前我们在控制台的命令行中输入python时所看到的方式。

因此,打开控制台,激活虚拟环境(读者现在对这个操作应该已经驾轻就熟)并输入python。此时,控制台将显示几行类似下面这样的信息:

(lpp3ed) mpro:my-project fab$ python
Python 3.9.2 (default, Mar 1 2021, 23:29:21)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

>>>是shell的输入提示符。它表示Python正等待我们输入内容。如果我们输入一条简单的指令,能够容纳于一行之中,它看上去就非常直观。但是,如果我们所输入的内容超过了一行,shell就会把输入提示符改变为…,该提示符给我们一种视觉提示,提醒我们正在输入一个多行语句(或其他任何需要多行代码的东西)。

继续,我们接着进行试验,完成一些基本的数学运算:

>>> 3 + 7
10
>>> 10 / 4
2.5
>>> 2 ** 1024
179769313486231590772930519078902473361797697894230657273430081157
732675805500963132708477322407536021120113879871393357658789768814
416622492847430639474124377767893424865485276302219601246094119453
082952085005768838150682342462881473913110540827237163350510684586
298239947245938479716304835356329624224137216

最后一个操作显示了令人难以置信的结果。我们取2的1024次幂,而Python非常轻松地完成了这个任务。如果在Java、C++或C#中尝试这样的做法,肯定会失败,除非使用能够处理这类巨大数值的特殊程序库。

我们每天都在使用交互式shell。它在快速调试方面极为实用,例如检查一种数据结构是否支持某个操作。或者,我们可以用它检查或运行一段代码。

当我们使用Django(一种Web框架)时,它附带了交互式shell,允许我们按照自己的方式使用这个框架的工具,对数据库中的数据进行检查或者执行其他许多操作。在学习Python的过程中,我们会发现交互式shell很快会成为我们亲密的伙伴之一。

另一种解决方案具有更漂亮的图形外观,称为集成开发和学习环境(Integrated Development and Learning Environment,IDLE)。这是一种相当简单的集成开发环境(Integrated Development Environment,IDE),主要是面向初学者。它的功能相比控制台中的原始交互式shell稍微强大一点,因此读者可能想对它进行探索。Windows操作系统的Python安装程序是免费的,可以很方便地把它安装在任何系统中。我们可以在Python网站上找到更多关于它的信息。

Guido Van Rossum以英国喜剧团Monty Python的名字为Python命名,所以有传言说IDLE这个名字是为了纪念Monty Python的创使人之一—Eric Idle。

1.8.3 以服务的形式运行Python

除了作为脚本运行或者在shell中运行之外,Python也可以编成代码以应用程序的形式运行。我们在本书中将会看到很多采用这种模式的例子。稍后当讨论如何组织和运行Python代码时,我们将会对此产生更深刻的理解。

1.8.4 以GUI应用程序的形式运行Python

Python也可以以图形用户界面(Graphical User Interface,GUI)的形式运行。我们可以使用几种框架,有些框架是跨平台的,也有些框架是某个平台特定的。在第12章中,我们将看到一个使用Tkinter创建的GUI应用程序的示例。Tkinter是一个面向对象的层,位于Tk(Tkinter的含义是Tk接口)的顶部。

Tk是一个GUI工具包,它将桌面应用程序开发提升到比传统方法更高的层次上。它是工具命令语言(Tool Command Language,TCL)的标准GUI,但也可用于许多其他动态语言。它可以生成丰富的本地应用程序,能够无缝地在Windows、Linux、macOS和其他操作系统中运行。

Tkinter已经集成到Python中,因此Python程序员可以很方便地访问GUI世界。基于这个原因,我们选择它作为本书所讲解的GUI示例的框架。

在其他GUI框架中,下面这些框架是最为常用的:

PyQt5/PySide 2;

wxPython;

Kivy。

对它们进行详细描述超出了本书的范围,但读者可以在Python官方网站的“What platform- independent GUI toolkits exist for Python?”(“Python存在哪些独立于平台的GUI工具包?”)一节中找到需要的所有信息。如果读者想要寻找一些GUI框架,记住要根据一些原则选择最适合的框架,确保它们满足下面的要求。

提供了开发项目时可能需要的所有特性。

能够在可能需要支持的所有平台上运行。

所依赖的社区尽可能庞大并且活跃。

包装了图形驱动程序和工具,使我们可以方便地安装和访问。

1.9 Python代码的组织形式

我们对Python代码的组织形式稍做讨论。在本节中,我们更深入一步,介绍一些技术性更强的名称和概念。

首先是最基本的概念,Python代码是如何组织的?当然,我们把代码编写在文件中。当我们用.py扩展名保存一个文件时,这个文件就成为一个Python模块

如果是在Windows或macOS这种一般会隐藏扩展名的操作系统中,我们建议对配置进行修改,以便看到完整的文件名。这并不是严格的要求,而是一个建议,它有助于对文件进行区分。

把软件需要的所有代码都保存在一个文件中是不切实际的。这种方法只适用于脚本,它的长度一般不会超过几百行(而且通常要比这个短得多)。

一个完整的Python应用程序可能由数十万行代码组成,因此我们不得不把它们划分到不同的模块中。这种做法要好一点,但还不够好。事实证明,就算采用了这种做法,我们在操作代码时仍然是非常麻烦的。因此,Python提供了另一种称为程序包(package)的结构,它允许我们把模块组合在一起。一个程序包就是一个简单的文件夹,但它必须包含一个特殊的文件__init__.py。这个文件并不需要包含任何代码,但是它的存在告诉Python这个文件夹不仅仅是个文件夹,而且还是个程序包。

和往常一样,我们用一个示例更加清楚地说明这些概念。我们在本书的项目中创建了一个示例结构,当我们在控制台中输入:

$ tree -v example

就可以看到ch1/example文件夹内容的树形表现形式,它包含了本章示例的代码。下面是一个相当简单的应用程序的结构:

example
├── core.py
├── run.py
└── util
 ├── __init__.py
 ├── db.py
 ├── math.py
 └── network.py

可以看到,这个例子的根目录中有两个模块:core.py和run.py,另外还有一个程序包util。core.py可能包含了这个应用程序的核心逻辑。在run.py模块中,我们很可能会发现这个应用程序的启动逻辑。在util程序包中,我们期望能够看到各种工具。事实上,我们可以猜到这些模块是根据它们所包含的工具的类型而命名的:db.py可能包含了操作数据库的工具,math.py可能包含了数学工具(这个应用程序可能需要处理金融数据),network.py可能包含了通过网络发送和接收数据的工具。

如前所述,__init__.py的作用就是告诉Python:util是一个程序包,而不仅仅是一个简单的文件夹。

如果这个软件只是在模块内部进行组织的,那么推断它的结构是非常困难的。我们把一个只含模块的示例放在ch1/files_only文件夹中,读者可以自行查阅:

$ tree -v files_only

这将展现一幅完全不同的画面:

files_only
├── core.py
├── db.py
├── math.py
├── network.py
└── run.py

要想猜出每个模块的功能有点难,是不是?现在,考虑到它只是一个简单的例子,因此我们可以想象,如果不采用程序包和模块的方式对代码进行组织,那么理解一个真正的应用程序将是一件多么困难的事情。

使用模块和程序包

当开发人员编写应用程序时,很可能需要把同一段逻辑应用于程序的不同部分。例如,为用户可能在网页上填写的数据编写解析器时,应用程序必须验证某个字段是否包含了数字。不管这种验证的逻辑是如何编写的,很可能有多个字段都需要使用这种逻辑。

例如,在一个投票应用程序中,用户需要回答多个问题,很可能有几个问题要求答案是数值形式的,如下所示。

您多大年纪?

您养了几只宠物?

您有几个孩子?

您结了几次婚?

在每个需要数值答案的地方复制粘贴(更正式的说法是重复)验证逻辑是一种非常糟糕的做法。这违反了“不要做重复劳动”(Don’t Repeat Yourself,DRY)的原则。这个原则表示我们在应用程序中不应该重复同一段代码超过一次。尽管DRY原则通俗易懂,我们觉得还是有必要在这里强调这个原则的重要性:绝对不要在应用程序中把同一段代码重复多次!

把同一段逻辑重复多次的做法之所以极为糟糕有很多原因,下面列出最重要的4个。

这段逻辑中可能会存在缺陷,因此我们不得不在这段逻辑的每份副本上都修正这个缺陷。

我们可能想要改进验证方式,同样不得不在它的每份副本上都进行修改。

我们可能忘记修正或改进某一段逻辑,因为我们在搜索时漏掉了它,这将导致应用程序中存在错误或不一致的行为。

代码在没有正当理由的情况下变得更长。

Python是一种出色的语言,为我们提供了实现最佳的编码实践需要的所有工具。在这个特定的例子中,我们需要复用一段代码。为了有效地实现这个目的,我们需要使用一种结构保存这段代码,这样每次当我们需要复制它所蕴含的逻辑时就可以调用这个结构。这样的结构确实存在,它就是函数

我们不打算在此深入介绍函数的特定细节,只需要记住函数是一段有组织的、可复用的代码,用于完成一个任务。根据函数所属的环境类型,它们可能具有不同的形式和不同的名称,但现在我们还不需要详细了解这一点。我们将在本书的后面真正领会函数的作用时领会这些细节。函数是应用程序模块化的基础构件,几乎是不可或缺的。除非我们所编写的是一个超级简单的脚本,否则肯定会用到函数。我们将在第4章中详细介绍函数。

如前所述,Python提供了一个非常全面的程序库。现在就是对程序库进行定义的良好时机:程序库是一些函数和对象的集合,提供了一些功能,从而丰富了语言的功能。例如,在Python的math库中,我们可以发现大量的函数,其中一个是factorial函数,它计算一个数的阶乘。

在数学中,非负整数N的阶乘用N !表示,其定义是小于或等于N的所有正整数的乘积。例如,5的阶乘的计算方式如下:

5! = 5×4×3×2×1 = 120

我们规定0的阶乘是0! = 1。

因此,如果我们想在自己的代码中使用这个函数,只需要将它导入并用正确的输入值调用它。现在,读者可能并不熟悉输入值和调用这两个概念,对此无须焦虑,请把注意力集中在重要的部分。当我们使用一个程序库时,可以导入这个程序库中我们所需要的功能并在代码中使用该功能。在Python中,为了计算5的阶乘,只需要下面的代码:

>>> from math import factorial
>>> factorial(5)
120

不管我们在shell中输入什么,如果它具有可输出的表示形式,都会在控制台中输出(在这个例子中,将会输出这个函数调用的结果:120)。

现在,让我们回到那个包含了core.py、run.py、util等内容的例子。在这个例子中,程序包util是工具程序库。我们的自定义工具belt包含了应用程序需要的所有可复用工具(即函数)。其中有些用于处理数据库(db.py),有些用于处理网络(network.py),有些所执行的数学计算(math.py)超出了Python标准库math的范围,因此我们不得不自己编写代码实现这些功能。

我们将在专门的章节中讲述如何导入和使用函数。现在,我们介绍另一个非常重要的概念:Python的执行模型

1.10 Python的执行模型

在本节中,我们将介绍一些非常重要的概念,例如作用域、名称和名字空间。当然,读者可以阅读官方语言参考,了解与Python的执行模型有关的所有信息。但是,我们觉得它的介绍技术性太强并且过于抽象,因此我们首先提供一个非正式的解释。

1.10.1 名称和名字空间

假设我们正在寻找一本书,因此来到图书馆并询问管理员自己想要借的书。管理员提供了类似“二楼,X区域,第3排”这样的信息。我们上楼之后找到X区域并继续寻找。如果一家图书馆的所有书籍都随机堆在一个大房间里——没有楼层、没有区域、没有书架、没有顺序,情况就大不相同。从这样的图书馆里寻找一本书是件极其困难的事情。

在编写代码的时候,我们会面临相同的问题:我们必须对代码进行组织,这样以前并不了解这些代码的人也可以很方便地找到他们所寻找的东西。当软件具有正确的结构时,可以提高代码的复用率。组织形式糟糕的软件很可能散布着大量具有重复逻辑的代码。

首先,我们以书为例子。用书名表示一本书,用Python的术语表示就是名称。Python的名称最接近于其他语言所称的变量。名称一般表示对象,是通过名称绑定操作所引入的。我们观察一个简单的例子(注意,#后面的内容是注释):

>>> n = 3 # 整数
>>> address = "221b Baker Street, NW1 6XE, London" # Sherlock Holmes的地址
>>> employee = {
... 'age': 45,
... 'role': 'CTO',
... 'SSN': 'AB1234567',
... }
>>> # 输出它们
>>> n
3
>>> address
'221b Baker Street, NW1 6XE, London'
>>> employee
{'age': 45, 'role': 'CTO', 'SSN': 'AB1234567'}
>>> other_name
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
NameError: name 'other_name' is not defined
>>>

记住,每个Python对象都具有标识、类型和值。在上面的代码中,我们定义了3个对象。下面我们解释它们的类型和值。

整数变量n(类型:int,值:3)。

字符串address(类型:str,值:Sherlock Holmes' address)。

字典employee(类型:dict,值:一个包含了3个键值对的字典对象)。

不要担心,现在不知道什么是字典是非常正常的。我们将在第2章中看到它是Python数据结构之王。

有没有注意到,当我们输入employee的定义之后,输入提示符从>>>变成了…?这是因为它的定义跨越了多行。

因此,n、address、employee是什么呢?它们是名称。我们可以使用名称在代码中提取数据。它们需要保存在某个地方,这样当我们需要提取那些对象时,就可以用名称来提取它们。我们需要一些空间保存它们,这个空间就是名字空间

名字空间就是从名称到对象的一种映射。名字空间的例子包括内置名称的集合(包含了所有Python程序可以访问的函数)、模块中的全局名称以及函数中的局部名称等。甚至一个对象的属性集合也可以看成一个名字空间。

名字空间的优美之处在于它们允许我们清晰地定义和组织名称,而不会出现重叠或冲突。例如,我们在图书馆所寻找的一本书的相关联名字空间就可以用于导入这本书本身,就像下面这样:

from library.second_floor.section_x.row_three import book

我们从名字空间library开始,通过点号操作符(.)进入这个名字空间。在这个名字空间中,找到second_floor并再次使用点号操作符。然后进入名字空间section_x,并在最后一个名字空间row_three中找到了我们想要寻找的名称:book。

当读者接触现实的代码例子时,很容易理解名字空间的概念。现在,读者只需要记住名字空间就是把名称与对象进行关联的场所就可以了。

另一个与名字空间密切相关的概念是作用域(scope),我们将对它进行简单的讨论。

1.10.2 作用域

根据Python官方文档的说法:

“作用域是Python程序的文本区域,可以在其中直接访问名字空间。”

可以直接访问意味着当我们查找一个未加限定引用的名称时,Python会试图在当前名字空间中查找。

作用域是静态确定的,但在运行时,它们实际上是被动态使用的。这意味着我们可以通过检查源代码,确定一个对象的作用域是什么。Python提供了4个可访问的不同作用域(当然,它们并不一定同时存在)。

局部作用域(local scope),它是最内层的作用域,包含了局部名称。

外层作用域(enclosing scope),它是所有外层函数的作用域。它包含了非局部的名称和非全局的名称。

全局作用域(global scope),包含了全局名称。

内置作用域(built-in scope),包含了内置的名称。Python提供了一组可以现成使用的函数,例如print、all、abs等。它们生存在内置作用域中。

规则如下:当我们引用一个名称时,Python首先在当前名字空间中寻找它。如果没有找到这个名称,Python就继续在外层作用域中寻找。这个过程一直持续,直到搜索完了内置作用域。如果在搜索了内置作用域之后仍未找到该名称,Python就会触发一个NameError异常,表示这个名称未被定义(在前面的例子中可以看到这个结果)。

因此,在寻找一个名称时,名字空间的搜索顺序是:局部、外层、全局、内置(LEGB)

这个描述过于抽象,因此下面我们观察一个例子。为了展示局部和外层作用域,我们必须定义一些函数。现在没有必要担心不熟悉定义函数的语法这个问题。我们将在第4章中介绍函数。现在只要记住,在下面的代码中,当我们看到def时,它表示定义了一个函数:

# scopes1.py
# 局部和全局作用域的比较
# 定义了一个称为local的函数
def local():
    m = 7
    print(m)
 
# 在全局作用域中定义了m
m = 5
 
# 调用(或执行)local函数
local()
 
print(m)

在上面这个例子中,我们定义了相同的名称m,它们分别位于全局作用域和局部作用域(local函数所定义的作用域)。当我们用下面的指令执行这个程序时(记得激活虚拟环境):

$ python scopes1.py

可以看到控制台所打印的两个数字:5和7。

Python解释器从上向下解析这个文件。首先,它找到几个注释行并将其忽略。其次,解析local函数的定义。当local函数被调用时,它执行两项任务:为表示数字7的对象设置一个名称并打印它。Python解释器继续执行自己的任务,并找到另一个名称绑定。这次的绑定发生在全局作用域,其值是5。下一行是对local函数的调用。当Python在这个时候执行这个函数时,局部作用域中发生了m = 7的绑定并将其打印出来。最后,Python调用了print函数,这个函数被执行,这次打印了5。

一个值得注意的重要事实是,属于local函数定义的那部分代码向右缩进了4个空格。事实上,Python是通过缩进代码来定义作用域的。通过缩进进入一个作用域,并通过取消缩进退出这个作用域。有些程序员使用2个空格的缩进,有些则使用3个空格的缩进,但建议使用的缩进数量是4个空格。这是一种最大限度地提高代码可读性的良好措施。以后,我们会进一步讨论在编写Python代码时应该遵循的所有约定。

在诸如Java、C#和C++这样的语言中,作用域是通过一对花括号{ … }而界定的。因此,在Python中,缩进代码对应于左花括号,取消缩进对应于右花括号。

如果我们删除m = 7这一行会发生什么呢?记住LEGB规则。Python首先会在局部作用域(local函数)中寻找m。由于没有找到,所以它会进入下一个外层作用域。在这个例子中,这个外层作用域就是全局作用域,因为local函数并没有出现在其他函数调用的内部。因此,我们将在控制台上看到数字5被打印了两次。下面我们观察这种情况下的代码是什么样的:

# scopes2.py
# 局部和全局作用域的比较
 
def local():
    # m并不属于local函数所定义的作用域
    # 因此Python将在下一个外层作用域中寻找
    # m 最终在全局作用域中找到
    print(m, 'printing from the local scope')
 
m = 5
print(m, 'printing from the global scope')
 
local()

运行scopes2.py将打印出下面的结果:

$ python scopes2.py
5 printing from the global scope
5 printing from the local scope

正如我们所预期的那样,Python首先打印m,然后当local函数被调用时,Python并没有在这个函数的作用域中找到m,因此Python沿着LEGB链继续寻找,直到在全局作用域中找到m。下面我们观察一个具有额外层的例子,也就是局部作用域和全局作用域之间有一个外层作用域:

# scopes3.py
# 局部、外层和全局作用域
 
def enclosing_func():
    m = 13
 
    def local():
        # m并不属于local函数所定义的作用域
        # 因此Python将会在外层作用域中寻找
        # 这次m是在外层作用域中找到的
        print(m, 'printing from the local scope')
 
    # 调用local函数
    local()
 
m = 5
print(m, 'printing from the global scope')
 
enclosing_func()

运行scopes3.py,将会在控制台上打印:

$ python scopes3.py
5, 'printing from the global scope'
13, 'printing from the local scope'

可以看到,local函数中的print指令像以前一样引用了m。m在这个函数中仍然是未定义的,因此Python按照LEGB顺序开始在外层作用域中寻找。这次,它在外层作用域中找到了m。

如果读者对这个过程仍然不是很清楚,不必心怀忧虑。随着我们不断地讲解本书的例子,读者迟早会彻底弄清这个过程。Python官方教程的“类”一节对作用域和名字空间有一段有趣的描述。如果读者想要更深入地理解这个主题,可以花点时间阅读这段内容。

在结束本章之前,我们简单介绍一下对象。不管怎样,Python中的所有东西都是对象,因此值得对它们进行更多的关注。

1.10.3 对象和类

1.1节在介绍对象时,提及了对象表示现实世界的物品。例如,我们如今通过网络销售所有种类的商品,需要能够适当地处理、存储和表示它们。但是,对象的实际含义要丰富得多。我们在Python中所完成的绝大部分工作都是对对象进行操作。因此,我们在此并不会详细介绍对象(将在第6章中深入讲解),只是对类和对象进行一些简要的介绍。

我们已经理解了对象是Python对数据的抽象。事实上,Python中的所有东西都是对象。数值、字符串(保存文本的数据结构)、容器、集合甚至函数都是对象。我们可以把对象看成至少具有3个特征的盒子:ID(独一无二的)、类型和值。

但它们是怎么出现的?我们是怎样创建它们的?我们应该怎样编写自定义对象?答案藏在一个简单的字“”中。

事实上,对象就是类的实例。Python的优美在于类本身也是对象,但我们现在不会深究这个概念。它引出了Python语言的高级概念之一:元类(metaclass)。现在最合适的方法是通过一个例子理解类和对象之间的区别。

假设有一位朋友说:“我买了一辆自行车!”我们立即就明白对方的意思。我们看到过这辆自行车吗?不。知道它的颜色吗?不。知道牌子吗?不。知道其他细节吗?不。

但是,我们已经知道了足够的信息,足以理解朋友所表示的“她买了一辆自行车”是什么意思。我们知道自行车有两个轮子装在车架上,还有车座、踏板、车把、刹车等配件。换句话说,即使我们没有看到过这辆自行车,仍然能够知道自行车这个概念。特性和特征的一组抽象集合组合在一起形成了一种称为“自行车”的东西。

在计算机编程中,这种抽象称为类。这个概念非常简单。类用于创建对象。换句话说,我们知道自行车是什么,我们知道这个类。但是,当我们的朋友有了她自己的自行车时,它就是自行车类的一个实例。她的自行车具有它自己的特征和方法。其他人也有自己的自行车,它们属于同一个类,但属于不同的实例。这个世界上的每辆自行车都是自行车类的一个实例。

下面我们观察一个例子。我们将编写一个定义自行车的类,然后创建两辆自行车,一辆红色的和一辆蓝色的。我们尽管使代码保持简单,但是如果读者仍然不能完全理解这些代码,也不必气馁。现在,我们只需要理解类和对象(或类的实例)之间的区别:

# bike.py
# 定义Bike类
class Bike:
 
    def __init__(self, colour, frame_material):
        self.colour = colour
        self.frame_material = frame_material
 
    def brake(self):
        print("Braking!")
 
# 创建几个实例
red_bike = Bike('Red', 'Carbon fiber')
blue_bike = Bike('Blue', 'Steel')
 
# 检查我们所拥有的对象,也就是Bike类的实例
print(red_bike.colour)  # 打印出:Red(红色)
print(red_bike.frame_material)  # 打印出:Carbon fiber(碳纤维)
print(blue_bike.colour)  # 打印出:Blue(蓝色)
print(blue_bike.frame_material)  # 打印出:Steel(钢)
 
# 刹车!
red_bike.brake()  # 打印出:Braking!(刹车!)

现在,我们希望已经不用再详细指导读者如何运行这个文件。每个代码块的第一行指定了文件名。要在Python模块中执行代码,只需运行$ python filename.py。

记住要激活虚拟环境。

这里有很多值得注意的有趣的事情。首先,类的定义是用class语句创建的。class语句后面的代码都被缩进,称为类体。在这个类中,类定义的最后一行是print("Braking!")。

定义了这个类之后,就可以创建一些实例了。可以看到,这个类的类体包含了两个方法的定义。简单地说,方法就是属于某个类的函数。

第一个方法__init__是这个类的初始化方法。它使用了Python的一些魔法,使用我们在创建对象时所传递的值来设置对象。

在Python中,每个具有前缀和后缀双下线的方法称为魔术方法。Python所使用的魔术方法具有很多不同的作用。因此,在创建自定义的方法时,不应该使用双下线作为方法名的前缀和后缀。这个命名约定最好保留给Python使用。

这个类所定义的另一个方法brake是我们在刹车时想要调用的方法。当然,它只包含了一条print语句。它仅仅是一个简单的例子而已。

因此,我们创建了两个Bike对象:一个为红色,采用了碳纤维的车架;另一个为蓝色,采用了钢制车架。在创建对象时向它们传递这些值。在创建之后,打印出红色自行车的颜色属性和车架类型,然后打印出蓝色自行车的车架类型。我们还调用了red_bike对象的brake方法。

最后还有一点值得注意。还记得我们曾经说过一个对象的属性集合也是一个名字空间吗?我们希望读者现在对这个概念已经有了更进一步的理解。可以看到,通过不同的名字空间(red_bike、blue_bike)获取frame_type属性可以得到不同的值。它们不会出现重叠,也不会发生冲突。

当然,这里的点号操作符(.)用于进入一个名字空间,它作用于对象时也是如此。

1.11 编写优质代码的指导原则

编写优质代码并不像看上去那么简单。如前所述,优秀的代码具有很多难以同时具备的品质。在某种程度上,编写优质代码是一门艺术。不管我们打算采用什么样的学习之路,有一样东西能够让我们的代码品质得到即刻的提升:PEP 8。

Python增强建议书(PEP)是一种文档,它描述了Python的新增特性。PEP还记录了围绕Python语言的开发过程,并提供了更基本的指南和信息。读者可以在Python官网找到所有PEP的索引。

PEP 8很可能是所有PEP中最著名的一个。它提出了一个简单但非常有效的指导方针集合,把Python定义为一种美学,使我们可以编写优美的Python代码。如果读者只能从本章得到一个建议,那就是:使用PEP 8,张开双手拥抱它。读者很快就会庆幸这个决定。

如今的编程不再是一种个人的登记/退出业务,它更像是一项需要社交能力的活动。几个开发人员共同协作,通过类似Git和Mercurial这样的工具共同开发一段代码,其结果就是一段代码很可能出自很多不同的开发人员之手。

Git和Mercurial很可能是如今最为常用的分布式修订控制系统。它们是非常重要的工具,其目的是帮助开发人员团队在同一个软件项目上实现协作。

现如今,我们较以往更加需要一种一致的方法编写代码,因此愈发强调了代码可读性的重要性。当一家公司的所有开发人员都遵循PEP 8时,一种非常可能出现的情况就是,任何人在接触一段代码时,觉得它就像是自己所编写的(对法布里奇奥来说,情况一直都是如此,他总是忘了哪些代码是他自己编写的)。

这就产生了一个显著的优点:当我们阅读符合自己编写习惯的代码时,就很容易理解它。如果没有这样的约定,每个程序员都按自己喜欢的方式组织代码,或者简单地按照他们所学到或习惯的方式编写代码,这意味着在理解每段代码时都必须了解编写者的个人风格。多亏了PEP 8,我们才可以避免这种情况。我们都是PEP 8的推崇者,在评价代码时,如果它不符合PEP 8的精神,就不会给予它太高的评价。因此,请花点时间研究这个建议书,它是非常重要的。

如今,Python开发人员可以使用一些不同的工具将他们的代码根据PEP 8的指导原则自动格式化。这类工具有一个称为black,它在最近几年非常流行。另外还有一些称为linter的工具,它们检查代码是否被正确地格式化,并向开发人员发出警告,指示如何修正错误。一种非常流行的linter是flake8。我们鼓励读者使用这些工具,因为它们可以简化使软件具有良好格式的任务。

在本书的示例中,我们尽量符合PEP 8的精神。遗憾的是,我们没有奢求每行代码不超过79个字符(这是PEP 8所推荐的每行代码的最大长度),也不得不削减一些空行和其他内容,但我们保证尽最大努力完善代码的布局,使它们尽可能地容易阅读。

1.12 Python的文化

Python在所有的编码行业中都得到了广泛的应用。许多不同的公司使用Python完成许多不同的工作,而且Python也广泛应用于教育领域(因为它的简洁性,所以它是一种优秀的教学语言,它的许多特性非常容易学习;它可以培养编写具有良好可读性代码的习惯;它与平台无关,并支持现代的面向对象编程范式)。

Python如今非常流行的一个原因是它的社区庞大、富有活力,并且聚集了大量优秀的人才。Python社区在全世界范围内组织了许多活动,大部分是围绕Python或它的Web主框架(如Django)进行的。

Python的源代码是开放的,它的支持者的思维也往往是非常开放的。访问Python网站的社区页面以获取更多信息并积极参与其中。

与Python有关的另一个现象是Python心理惯性。事实上,Python允许我们使用一些其他语言所没有的惯用法,至少在形式上明显不同或者在其他语言中不容易实现(现在,当我们用一种非Python语言编写代码时,就会产生恐慌感)。

不管怎样,在过去的几年里,确实出现了Python心理惯性。按照我们的理解,它有点类似于“按照Python所建议的方式做其他任何事情”。

为了帮助读者更好地理解Python的文化和Python心理惯性,我们特意展示了Python之禅。这是一个非常流行的复活节彩蛋。打开Python控制台并输入import this,就会出现下面的输出[1]

[1] “Python之禅”有众多版本的译文,读者可以自行搜索。——编者注

>>> 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! 

这里存在两个层次的理解。一个层次是把它看成一组通过有趣的方式组织而成的指导方针,另一个层次是把它记在心里,偶尔温故知新,加深对它的理解:我们可能必须深入理解一些Python特征,才能按照预想的方式编写Python代码。从有趣出发,然后深入挖掘。总是要想办法挖掘得更深。

1.13 关于IDE的说明

我们在这里简单地讨论一下IDE。为了运行本书的所有例子,并不需要使用IDE。所有的文本编辑器都可以很好地完成任务。如果需要更高级的特性,例如语法特殊颜色显示和自动完成等,可以使用IDE。读者可以在Python的网站上找到大量开放源代码的IDE(只要在搜索引擎中搜索“Python IDE”)。

法布里奇奥使用Microsoft的Visual Studio Code。它是免费的并提供了丰富的功能,可以通过安装扩展进行增强。多年以来使用过好几个编辑器(包括Sublime Text)之后,他觉得这个编辑器对他来说是效率最高的。

海因里希则是Vim的铁杆用户。尽管Vim的学习曲线陡峭,但它是一种功能非常强大的文本编辑器,还支持用插件进行扩展。它还有一个优点,就是可以安装在软件开发人员所使用的几乎所有系统中。

两个重要的建议如下。

不管选择使用哪个IDE,都要充分了解它,尽可能地发挥它的长处。但是,不要过分依赖它。偶尔要尝试用Vim(或其他任何文本编辑器)进行工作,学会在任何平台上使用任何工具集都可以工作。

不管使用的哪种文本编辑器或IDE,在编写Python代码时,保持缩进为4个空格。不要使用Tab键,不要混用Tab键和空格。使用4个空格,而不是2个、3个或5个,就是使用4个。其他人也都采用这样的约定,我们不会因为自己使用3个空格的缩进而被看成是异类。

1.14 总结

在本章中,我们开始探索编程世界并初步了解了Python。在学习之旅中,我们仅仅触及了表面,只是稍稍接触了一些概念。我们将在本书的后面详细讲解这些概念。

我们讨论了Python的主要特性、它的用户以及它的用途,并讨论了编写Python程序的不同方法。

在本章的最后,我们简单讨论了名字空间、作用域、类、对象的基本概念。我们还看到了如何使用模块和程序包组织Python代码。

在实践层面,我们学习了怎样在系统中安装Python、怎样保证自己所需要的工具(如pip)已经就绪。我们还创建并激活了第一个虚拟环境,后者允许我们在一个自包含的环境中工作,而不用冒着与Python的系统安装发生冲突的风险。

现在,大家已经准备好了跟随我们进行本书的学习之旅。我们所需要的就是热情、一个激活的虚拟环境、本书、双手和一杯咖啡。

读者应该尝试运行本章的示例。我们尽量使它们保持简短。如果亲手输入这些例子并运行,相比仅仅阅读它们,无疑能够留下更深刻的印象。

在第2章中,我们将探索Python丰富的内置数据类型集合。对于这个主题,我们有大量的东西需要学习!

读者服务:

微信扫码关注【异步社区】微信公众号,回复“e60738”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。

相关图书

深度学习的数学——使用Python语言
深度学习的数学——使用Python语言
动手学自然语言处理
动手学自然语言处理
Python高性能编程(第2版)
Python高性能编程(第2版)
图像处理与计算机视觉实践——基于OpenCV和Python
图像处理与计算机视觉实践——基于OpenCV和Python
Python数据科学实战
Python数据科学实战
Web应用安全
Web应用安全

相关文章

相关课程