Python for Everybody 中文版

Chapter 0 Base Material

| 关于   «  Chapter 0 Base Material   ::   目录   ::   2. PY4E - Python 为所有人  »

1. PY4E - Python 为所有人

切换导航

PY4E

第 1 章:简介 第 2 章:变量 第 3 章:条件语句 第 4 章:函数 第 5 章:循环 第 6 章:字符串 第 7 章:文件 第 8 章:列表 第 9 章:字典 第 10 章:元组 第 11 章:正则表达式 第 12 章:网络程序 第 13 章:Python 与 Web 服务 第 14 章:Python 对象 第 15 章:Python 与数据库 第 16 章:数据可视化

使用 Python 3 探索数据

Charles R. Severance 博士

1.1. 为什么要学习编写程序?

编写程序(或编程)是一项非常具有创造性和回报的活动。你可以出于多种原因编写程序,从谋生到解决复杂的数据分析问题,再到娱乐或帮助他人解决问题。本书假设 每个人 都需要掌握编程技能,并且一旦你学会了编程,你就能弄清楚如何利用这些新获得的技能。

在我们日常生活中,我们被各种计算机所包围,从笔记本电脑到手机。我们可以将这些计算机视为我们的“个人助手”,它们可以替我们处理很多事情。当今计算机的硬件本质上被构建为持续地向我们提问:“您希望我接下来做什么?”

Personal Digital Assistant

个人数字助理

程序员在硬件上添加操作系统和一组应用程序,最终我们得到了一个个人数字助理,它非常有用,能够帮助我们完成许多不同的任务。

我们的计算机运算速度极快,拥有巨大的内存量,如果我们知道一种语言来向计算机解释我们希望它“接下来做什么”,那么它们就能对我们非常有帮助。如果我们知道这种语言,就可以让计算机替我们执行重复性的任务。有趣的是,计算机最擅长做的事情往往正是我们人类觉得枯燥乏味、令人麻木的事情。

例如,查看本章的前三段,告诉我使用最频繁的单词及其出现次数。虽然你能在几秒钟内阅读并理解这些单词,但统计它们几乎令人痛苦,因为这不是人类大脑设计用来解决的问题。对于计算机而言,情况恰恰相反:从纸上阅读和理解文本对计算机来说很困难,但统计单词并告诉你使用最频繁的单词出现了多少次对计算机来说非常容易:

python words.py
Enter file:words.txt
to 16

我们的“个人信息分析助手”很快告诉我们,单词"to"在本章前三段中使用了十六次。

正是计算机擅长人类不擅长的事物这一事实,使得你需要掌握“计算机语言”的对话技巧。一旦你学会了这门新语言,你就可以将琐碎的任务委托给你的伙伴(计算机),从而腾出更多时间去做你独具天赋的事情。你为这种伙伴关系带来了创造力、直觉和发明才能。

1.1.1. 创造力与动机

虽然本书并非专为职业程序员编写,但职业编程在财务和个人层面都可能是一份非常有回报的工作。为其他人构建有用、优雅且巧妙的程序是一项极具创造性的活动。您的计算机或个人数字助理(PDA)通常包含来自许多不同程序员群体的多种程序,它们各自竞争您的注意力和兴趣。它们竭尽全力满足您的需求,并在过程中为您提供卓越的用户体验。在某些情况下,当您选择某款软件时,程序员会因您的选择而直接获得报酬。

如果我们把程序视为程序员群体的创造性产出,那么下图或许是我们 PDA 更合理的版本:

Programmers Talking to You

程序员与你交谈

目前,我们的主要动机不是赚钱或取悦最终用户,而是为了让我们在处理生活中遇到的数据和信息时更加高效。当你刚开始时,你既是程序的程序员,也是程序的最终用户。随着你作为程序员的技能提升,编程对你来说感觉更具创造性,你的想法可能会转向为其他人开发程序。

1.1.2. 计算机硬件架构

在我们开始学习用来向计算机发出指令以开发软件的语言之前,我们需要了解计算机是如何构建的。如果你拆开你的计算机或手机并深入观察内部,你会发现以下部件:

Hardware Architecture

硬件架构

这些部分的高级定义如下:

  • 中央处理器 (或 CPU)是计算机中专注于“下一步是什么?”的部分。如果您的计算机标称为 3.0 千兆赫,这意味着 CPU 每秒会询问“下一步是什么?”三十亿次。您将必须学会如何快速交流,才能跟上 CPU 的节奏。

  • 主存储器 用于存储 CPU 急需的信息。主存储器的速度几乎与 CPU 相当。但是,当计算机关闭时,存储在主存储器中的信息就会消失。

  • Secondary Memory 也用于存储信息,但其速度远慢于主存。二级存储的优势在于,即使计算机断电,它仍能保存信息。二级存储的例子包括磁盘驱动器或闪存(通常存在于 USB 闪存盘和便携式音乐播放器中)。

  • 输入输出设备 仅仅是我们的屏幕、键盘、鼠标、麦克风、扬声器、触摸板等。它们都是我们与计算机交互的方式。

  • 如今,大多数计算机还拥有一个 网络连接 ,用于通过网络检索信息。我们可以将网络视为一个存储和检索数据的地方,其速度可能并不总是“在线”。因此,从某种意义上说,网络是一种更慢且有时不可靠的 辅助存储器 形式。

虽然这些组件的工作原理的绝大部分细节最好留给计算机构建者,但拥有一些术语有助于我们在编写程序时讨论这些不同的部分。

作为程序员,你的工作是使用并协调这些资源来解决你需要解决的问题,并分析从解决方案中获得的数据。作为程序员,你主要是在与 CPU“对话”,告诉它下一步要做什么。有时你会告诉 CPU 使用主存储器、辅助存储器、网络或输入/输出设备。

Where Are You?

你在哪里?

你需要成为那个回答 CPU“接下来做什么?”问题的人。但将你缩小到 5mm 高并插入计算机中,以便每秒发出 30 亿次指令,这会让你感到非常不适。因此,你必须提前写下你的指令。我们将这些存储的指令称为 program ,而将这些指令写下来并确保其正确性的过程称为 programming 。

1.1.3. 理解编程

在本书的其余部分,我们将努力将你培养成精通编程艺术的人。最终,你将成为一名 程序员 - 也许你不是职业程序员,但至少你将具备 审视数据/信息分析问题并开发程序解决该问题的技能。

从某种意义上说,要成为一名程序员需要两种技能:

  • 首先,你需要了解编程语言(Python)——你需要掌握其词汇和语法。你需要能够正确地拼写这种新语言中的单词,并知道如何构建这种新语言中结构良好的“句子”。

  • 其次,你需要“讲述一个故事”。在撰写故事时,你将单词和句子组合起来,向读者传达一个想法。构建故事需要技巧和艺术,而写作技巧可以通过实际写作并获得反馈来提升。在编程中,我们的程序就是“故事”,而你试图解决的问题就是“想法”。

一旦你学会一门编程语言(如 Python),你就会发现学习第二门编程语言(如 JavaScript 或 C++)要容易得多。新的编程语言拥有非常不同的词汇和语法,但解决问题的能力在所有编程语言中都是相同的。

您将很快学会 Python 的“词汇”和“句子”。要能够编写连贯的程序来解决全新的问题,则需要更长的时间。我们教授编程的方式很像教授写作。我们先阅读和解释程序,然后编写简单的程序,随着时间的推移,再编写越来越复杂的程序。在某个时刻,您会“获得灵感”,自己看到模式,并更自然地看到如何将问题转化为解决该问题的程序。一旦到达那个阶段,编程就会成为一个非常愉快且富有创造力的过程。

我们从 Python 程序的字词和结构开始。请耐心一些,简单的例子会提醒你初次阅读时的感觉。

1.1.4. 单词和句子

与人类语言不同,Python 词汇量实际上非常小。我们将这种“词汇”称为“保留字”。这些词对 Python 具有非常特殊的含义。当 Python 在 Python 程序中看到这些词时,它们对 Python 有且只有一种含义。稍后,当您编写程序时,您将创建对您有意义的词,称为 变量 。您在为变量选择名称时有很大的自由度,但不能使用 Python 的任何保留字作为变量的名称。

当我们训练一只狗时,我们会使用像“坐下”、“待着”和“取回”这样的特殊词汇。当你与狗交谈而不使用任何保留词时,它们只是用一种困惑的表情看着你,直到你说出一个保留词。例如,如果你说,“我希望更多人能步行以提高他们的整体健康”,大多数狗听到的很可能是,“blah blah blah walk blah blah blah blah。”这是因为“步行”是狗语言中的一个保留词。许多人可能会建议,人类与猫之间的语言没有保留词:sup:`1 <https://www.py4e.com/html3/01-intro#fn1>`__。

人类与 Python 交流的语言中的保留字包括以下:

and       del       global      not       with
as        elif      if          or        yield
assert    else      import      pass
break     except    in          raise
class     finally   is          return
continue  for       lambda      try
def       from      nonlocal    while

就是这样,与狗不同,Python 已经完全训练好了。当你说“try”时,Python 每次你说它都会尝试,从不失败。

我们将在适当的时候学习这些保留字及其用法,但目前我们将专注于 Python 中"speak"(在人与狗的对话语言中)的等价物。告诉 Python 说话的好处在于,我们可以通过给它一个带引号的字符串来指定它要说什么:

print('Hello world!')

并且我们甚至写出了第一句语法正确的 Python 语句。我们的语句以函数 print 开头,后跟一段用单引号括起来的文本字符串。print 语句中的字符串也用引号括起来。单引号和双引号的作用相同;大多数人使用单引号,除非像这种情况,字符串中包含单引号(这也是撇号)。

1.1.5. 与 Python 对话

现在我们已经掌握了 Python 中的单词和简单句子,我们需要知道如何启动与 Python 的对话以测试我们的新语言技能。

在与 Python 对话之前,您必须首先在计算机上安装 Python 软件,并学习如何在计算机上启动 Python。本章节的内容过于详细,因此建议您查阅 www.py4e.com,其中详细说明了在 Macintosh 和 Windows 系统上设置和启动 Python 的说明及屏幕录像。在某个时刻,您将处于终端或命令窗口中,并输入 python ,此时 Python 解释器将以交互模式开始执行,并大致如下所示:

Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:54:25)
[MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more
information.
>>>

>>> 提示符是 Python 解释器询问你“下一步想让我做什么”的方式。Python 已准备好与你进行对话。你只需知道如何说 Python 语言即可。

假设您甚至不知道最简单的 Python 语言词汇或句子。您可能希望使用宇航员在降落到遥远星球时使用的标准台词,并尝试与该星球的居民交谈:

>>> I come in peace, please take me to your leader
File "<stdin>", line 1
  I come in peace, please take me to your leader
       ^
SyntaxError: invalid syntax
>>>

情况并不乐观。除非你能迅速想出对策,否则这个星球的居民很可能会用长矛刺你,把你串在烤叉上,在火上烤熟,然后把你当作晚餐吃掉。

幸运的是,你在旅途中带了一本这本书的副本,你翻到这一页并再次尝试:

>>> print('Hello world!')
Hello world!

这看起来好多了,因此你尝试再多沟通一些:

>>> print('You must be the legendary god that comes from the sky')
You must be the legendary god that comes from the sky
>>> print('We have been waiting for you for a long time')
We have been waiting for you for a long time
>>> print('Our legend says you will be very tasty with mustard')
Our legend says you will be very tasty with mustard
>>> print 'We will have a feast tonight unless you say
File "<stdin>", line 1
  print 'We will have a feast tonight unless you say
                                                   ^
SyntaxError: Missing parentheses in call to 'print'
>>>

对话进行得相当顺利,一段时间之后,你在使用 Python 语言时犯了一个极小的错误,Python 便重新唤出了长矛。

此时,你也应该意识到,虽然 Python 极其复杂、功能强大,并且对你用来与它通信的语法要求非常严格,但 Python 不是 智能的。你实际上只是在用正确的语法与自己对话。

从某种意义上说,当你使用他人编写的程序时,这场对话是在你与其他程序员之间进行的,而 Python 充当着中间人。Python 是程序创作者表达对话应如何进行的一种方式。再过几章,你也将成为那些使用 Python 与你的程序用户进行交流的程序员之一。

在与 Python 星球的居民互动之前,在我们结束与 Python 解释器的第一次对话之前,您可能应该知道如何正确地告别:

>>> good-bye
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'good' is not defined
>>> if you don't mind, I need to leave
File "<stdin>", line 1
  if you don't mind, I need to leave
           ^
SyntaxError: invalid syntax
>>> quit()

您将注意到,前两次尝试的错误是不同的。第二次错误之所以不同,是因为 if 是一个保留字,Python 看到了该保留字并认为我们试图表达某种含义,但句子的语法不正确。

告别 Python 的正确方法是进入交互式提示符 >>> 后输入 quit() 。你大概需要花很长时间才能猜到这一点,所以手边有一本书可能会很有帮助。

1.1.6. 术语:解释器和编译器

Python 是一种 高级 语言,旨在让人类易于阅读和编写,同时也便于计算机读取和处理。其他高级语言包括 Java、C++、PHP、Ruby、Basic、Perl、JavaScript 以及更多。中央处理器(CPU)内部的硬件并不理解这些高级语言中的任何一种。

CPU 理解一种我们称之为 机器语言 的语言。机器语言非常简单,而且坦白地说非常难以编写,因为它完全由零和一表示:

001010001110100100101010000001111
11100110000011101010010101101101
...

机器语言表面上看起来非常简单,因为其中只有 0 和 1,但其语法甚至比 Python 更加复杂且错综复杂。因此,很少有程序员编写机器语言。相反,我们构建各种翻译器,允许程序员使用 Python 或 JavaScript 等高级语言编写代码,这些翻译器将程序转换为机器语言,以便 CPU 实际执行。

由于机器语言与计算机硬件绑定,机器语言无法在不同类型的硬件之间 移植 。使用新机器上的不同解释器或将代码重新编译以创建新机器的机器语言版本,就可以将用高级语言编写的程序移动到其他计算机上。

这些编程语言翻译器分为两大类:(1) 解释器和 (2) 编译器。

解释器( interpreter )读取程序员编写的程序源代码,解析源代码,并即时解释指令。Python 是一种解释器,当我们交互式运行 Python 时,可以输入一行 Python 代码(一个句子),Python 会立即处理它,并准备好让我们输入下一行 Python 代码。

Python 代码的某些行告诉 Python 你希望它记住某个值以供以后使用。我们需要为该值选择一个名称以便记住它,之后可以使用该符号名称来检索该值。我们使用术语 变量 来指代我们用来引用这些存储数据的标签。

>>> x = 6
>>> print(x)
6
>>> y = x * 7
>>> print(y)
42
>>>

在本例中,我们要求 Python 记住值 six 并使用标签 x ,以便稍后检索该值。我们使用 print 验证 Python 是否确实记住了该值。然后我们要求 Python 检索 x ,将其乘以 seven,并将新计算出的值放入 y 。然后我们要求 Python 打印出 y 中当前的值。

尽管我们逐行将这些命令输入到 Python 中,Python 将它们视为一个有序的语句序列,后面的语句能够检索前面语句创建的数据。我们正在以逻辑且有意义的方式编写第一个包含四个句子的简单段落。

解释器的特性是能够进行如上所示的交互式对话。编译器需要将整个程序作为文件传入,然后运行一个过程将高级源代码翻译成机器语言,随后编译器将生成的机器语言放入文件中以便稍后执行。

如果您拥有 Windows 系统,这些可执行机器语言程序通常具有".exe"或".dll"的后缀,分别代表"executable"和"dynamic link library"。在 Linux 和 Macintosh 中,没有后缀能唯一标记文件为可执行文件。

如果您在文本编辑器中打开一个可执行文件,它会看起来完全混乱且无法阅读:

^?ELF^A^A^A^@^@^@^@^@^@^@^@^@^B^@^C^@^A^@^@^@\xa0\x82
^D^H4^@^@^@\x90^]^@^@^@^@^@^@4^@ ^@^G^@(^@$^@!^@^F^@
^@^@4^@^@^@4\x80^D^H4\x80^D^H\xe0^@^@^@\xe0^@^@^@^E
^@^@^@^D^@^@^@^C^@^@^@^T^A^@^@^T\x81^D^H^T\x81^D^H^S
^@^@^@^S^@^@^@^D^@^@^@^A^@^@^@^A\^D^HQVhT\x83^D^H\xe8
....

阅读或编写机器语言并不容易,因此拥有允许我们用 Python 或 C 等高级语言编写的 解释器 和 编译器 是很好的。

现在在我们讨论编译器和解释器时,你可能对 Python 解释器本身产生了一些疑问。它用何种语言编写?是用编译型语言编写吗?当我们键入"python"时,究竟发生了什么?

之前的 Python 解释器是用一种名为"C"的高级语言编写的。你可以通过访问 www.python.org 并逐步查看其源代码来查看 Python 解释器的实际源代码。因此,Python 本身就是一个程序,并被编译成机器代码。当你将 Python 安装到你的计算机上(或供应商安装它)时,你将翻译后的 Python 程序的机器代码副本复制到了你的系统上。在 Windows 中,Python 本身的可执行机器代码可能位于一个名为:

C:\Python35\python.exe

这比你真正需要知道的 Python 编程知识要多,但有时在开始时回答那些小问题是值得的。

1.1.7. 编写程序

在 Python 解释器中输入命令是探索 Python 功能的好方法,但不建议用于解决更复杂的问题。

当我们想要编写程序时,我们使用文本编辑器将 Python 指令写入到一个文件中,该文件称为一个 script 。按照惯例,Python 脚本的名称以 .py 结尾。

要执行该脚本,您必须告诉 Python 解释器文件名。在命令窗口中,您会像下面这样输入 python hello.py :

$ cat hello.py
print('Hello world!')
$ python hello.py
Hello world!

"$" 是操作系统的提示符,而 "cat hello.py" 向我们显示文件 "hello.py" 包含一个单行 Python 程序用于打印字符串。

我们调用 Python 解释器,并指示它从文件"hello.py"读取源代码,而不是交互式地提示我们输入 Python 代码行。

您将注意到,在文件中的 Python 程序末尾并不需要 quit() 。当 Python 从文件读取您的源代码时,它知道在到达文件末尾时停止。

1.1.8. 什么是程序?

在最基本的层面上,对 程序 的定义是一系列精心设计的 Python 语句,用于完成某项任务。即使是我们简单的 hello.py 脚本也是一个程序。它是一个单行程序,并不特别有用,但在最严格的定义下,它是一个 Python 程序。

理解程序可能最简单的方法是思考程序可能用于解决的问题,然后查看一个能解决该问题的程序。

假设您正在进行关于 Facebook 帖子的社会计算研究,并且您感兴趣的是系列帖子中最常用的单词。您可以打印出 Facebook 帖子的流,并仔细查看文本以寻找最常见的单词,但这将花费很长时间且非常容易出错。明智的做法是编写一个 Python 程序来快速准确地处理该任务,这样您就可以利用周末做一些有趣的事情。

例如,查看下面关于小丑和汽车的文本。查看文本并找出最常见的单词及其出现次数。

the clown ran after the car and the car ran into the tent
and the tent fell down on the clown and the car

然后想象一下,你正在查看数百万行文本来完成这项任务。老实说,你学习 Python 并编写一个 Python 程序来统计单词,比手动扫描单词要快得多。

更好的消息是,我已经编写了一个简单的程序来查找文本文件中最常见的单词。我编写了它,测试了它,现在把它提供给你使用,以便你可以节省一些时间。

name = input('Enter file:')
handle = open(name, 'r')
counts = dict()

for line in handle:
    words = line.split()
    for word in words:
        counts[word] = counts.get(word, 0) + 1

bigcount = None
bigword = None
for word, count in list(counts.items()):
    if bigcount is None or count > bigcount:
        bigword = word
        bigcount = count

print(bigword, bigcount)

# Code: http://www.py4e.com/code3/words.py

您甚至不需要了解 Python 即可使用本程序。您需要读完本书第 10 章,才能完全理解用于编写本程序的出色 Python 技术。您是最终用户,只需使用程序并惊叹于其巧妙之处以及它为您节省了多少手工劳动。您只需将代码输入到一个名为 words.py 的文件中并运行它,或者从 http://www.py4e.com/code3/ 下载源代码并运行它。

这是一个很好的例子,说明了 Python 和 Python 语言如何在你(最终用户)和我(程序员)之间充当中介。Python 是我们用一种共同语言交换有用的指令序列(即程序)的方式,任何在电脑上安装了 Python 的人都可以使用这种语言。因此,我们双方都不是在与 Python 对话,而是 通过 Python 相互沟通。

1.1.9. 程序的构建模块

在接下来的几章中,我们将学习更多关于 Python 的词汇、句子结构、段落结构和故事结构。我们将学习 Python 的强大功能以及如何组合这些功能来创建有用的程序。

我们使用一些低级概念模式来构建程序。这些结构不仅适用于 Python 程序,它们是每种编程语言的一部分,从机器语言到高级语言。

input

从“外部世界”获取数据。这可能是从文件读取数据,甚至是来自麦克风或 GPS 等传感器的数据。在我们的初始程序中,输入将来自用户在键盘上键入的数据。

output

在屏幕上显示程序的结果,或将它们存储在文件中,又或者将它们写入扬声器等设备以播放音乐或朗读文本。

sequential execution

按照脚本中遇到的顺序依次执行语句。

conditional execution

检查特定条件,然后执行或跳过一系列语句。

repeated execution

重复执行某组语句,通常带有一些变化。

reuse

编写一组指令一次并为其命名,然后在整个程序中根据需要重用这些指令。

这听起来几乎过于简单而不真实,当然它从未如此简单。这就像说走路仅仅是“把一只脚放在另一只脚前面”。编写程序的“艺术”在于多次组合和编织这些基本元素,以生产出对用户有用的东西。

上述单词计数程序直接使用了所有这些模式,除了一个。

1.1.10. 可能出什么错?

正如我们在最早与 Python 的对话中所见,当我们编写 Python 代码时,必须非常精确地传达指令。哪怕是最微小的偏差或错误,都会导致 Python 停止查看你的程序。

初学编程的人常常认为 Python 不留任何容错空间是 Python 刻薄、仇恨且残忍的证据。虽然 Python 似乎喜欢其他人,但它认识他们每一个人,并对他们怀恨在心。由于这种怨恨,Python 会拒绝我们写得完美的程序,称其“不合格”,仅仅为了折磨我们。

>>> primt 'Hello world!'
File "<stdin>", line 1
  primt 'Hello world!'
                     ^
SyntaxError: invalid syntax
>>> primt ('Hello world')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'primt' is not defined

>>> I hate you Python!
File "<stdin>", line 1
  I hate you Python!
       ^
SyntaxError: invalid syntax
>>> if you come out of there, I would teach you a lesson
File "<stdin>", line 1
  if you come out of there, I would teach you a lesson
            ^
SyntaxError: invalid syntax
>>>

与 Python 争论几乎没有收获。它仅仅是一个工具。它没有情感,并且随时准备在你需要时为你服务。它的错误信息听起来很严厉,但这只是 Python 的求助信号。它已经查看了你所输入的内容,但它根本无法理解你输入了什么。

Python 更像是一只狗,它无条件地爱你,理解几个关键字,用甜美的目光看着你( >>> ),然后等待你说出它听得懂的话。当 Python 说“SyntaxError: invalid syntax"时,它只是在摇尾巴,说:“你似乎说了些什么,但我就是不明白你的意思,但请继续和我说话( >>> )。”

随着您的程序变得越来越复杂,您会遇到三种通用类型的错误:

语法错误 这些是你最先会犯的错误,也是最容易修复的。语法错误意味着你违反了 Python 的“语法”规则。Python 会尽力指出它感到困惑的行和字符。语法错误中唯一棘手的地方是,有时需要修复的错误实际上出现在 Python 注意到 困惑之处之前的程序中。因此,Python 在语法错误中指示的行和字符可能只是你调查的起点。逻辑错误 逻辑错误是指你的程序语法良好,但语句顺序有误,或者语句之间的关系存在错误。逻辑错误的一个好例子可能是,“从水瓶中喝一口水,把它放进背包,走到图书馆,然后把瓶盖盖回去”。语义错误 语义错误是指你对所采取步骤的描述在语法上是完美的且顺序正确,但程序中确实存在错误。程序在语法上是完全正确的,但它没有按你 期望 的方式运行。一个简单的例子是,如果你给某人指路去一家餐厅,并说,“……当你到达加油站路口时,向左转,走一英里,餐厅就在你左边的红色建筑里。”你的朋友很晚才给你打电话,告诉你他们在一个农场,正在谷仓后面转悠,没有任何餐厅的迹象。然后你说“你在加油站是向左转还是向右转?”他们回答说,“我完全按照你的指示行事,我有书面记录,上面写着在加油站向左转,走一英里。”然后你说,“非常抱歉,因为虽然我的指示在语法上是正确的,但它们不幸包含了一个虽小但未被发现的语义错误。”

再次,在所有三种类型的错误中,Python 只是尽最大努力完全执行您要求的操作。

1.1.11. 调试

当 Python 抛出错误,甚至给出与你预期不同的结果时,便开始寻找错误原因。调试是找出代码中错误原因的过程。当你正在调试一个程序时,尤其是当你正在处理一个棘手的问题时,有四种方法可以尝试:

阅读

检查你的代码,读给自己听,并确认它表达了你想表达的意思。

运行

通过进行修改并运行不同版本来进行实验。如果在程序的正确位置显示正确的内容,问题就会变得显而易见,但有时你需要花一些时间来搭建脚手架。

沉思

花些时间思考!错误属于哪种类型:语法错误、运行时错误还是语义错误?你可以从错误消息或程序输出中获得什么信息?可能导致你所见问题的错误属于哪种类型?在问题出现之前,你最后做了什么改动?

撤退

在某个时刻,最好的做法是退后,撤销最近的修改,直到回到一个你理解且能运行的程序。然后你可以开始重新构建。

初学者有时会陷入这些活动中的某一项而忘记其他活动。发现一个难以解决的 bug 需要阅读、运行、沉思,有时还需要撤退。如果你在某项活动中卡住了,请尝试其他活动。每项活动都有其自身的失败模式。

例如,阅读代码可能在问题为拼写错误时有所帮助,但如果问题是概念性误解则无济于事。如果你不理解程序的作用,即使阅读 100 遍也永远找不到错误,因为错误在你脑海中。

运行实验会有所帮助,尤其是当你运行小型、简单的测试时。但如果你在不思考或不阅读代码的情况下运行实验,你可能会陷入我称之为“随机游走编程”的模式,即通过进行随机更改直到程序做出正确行为的过程。不用说,随机游走编程可能会花费很长时间。

你必须花时间思考。调试就像是一门实验科学。你至少应该有一个关于问题是什么的假设。如果有两个或更多的可能性,试着想一个测试来排除其中一个。

休息一下有助于思考。交谈也有同样的效果。如果你向另一个人(甚至自己)解释问题,有时你会在问完问题之前就找到答案。

但即使最好的调试技术,如果错误过多,或者您试图修复的代码过于庞大和复杂,也会失效。有时最好的选择是退后,简化程序,直到得到一个既有效又易于理解的结果。

初学编程者往往不愿退让,因为他们无法忍受删除一行代码(即使它是错误的)。如果这让你感觉好受些,请在开始精简程序之前将其复制到另一个文件中。然后你可以一点一点地将片段粘贴回去。

1.1.12. 学习之旅

随着你在本书其余部分的深入,如果概念初次看起来并不契合,请不要害怕。当你学习说话时,头几年只是发出可爱的咕咕声并不是问题。从简单词汇过渡到简单句子花费六个月,从句子过渡到段落又花费 5-6 年,再花几年才能独立写出有趣的完整短篇故事,这都是可以的。

我们要您更快速地学习 Python,因此我们将在接下来的几章中同时教授所有内容。但这就像学习一门新语言一样,需要时间吸收和理解,直到感觉自然。这导致了一些困惑,因为我们在访问和重温主题时,试图让您看到大局,同时定义构成大局的微小片段。虽然本书是按线性编写的,如果您正在修读课程,它将按线性方式推进,但请不要犹豫,以非常非线性的方式接近材料。向前看和向后看,以轻松的笔触阅读。通过浏览更高级的材料而不完全理解细节,您可以更好地理解编程的“为什么”。通过回顾之前的材料甚至重新完成早期的练习,您将意识到,即使您当前盯着的材料似乎有点难以理解,您实际上也学到了很多材料。

通常,当你学习第一种编程语言时,会有几个美妙的“啊哈!”时刻,你可以从用锤子和凿子敲打岩石中抬起头来,退后一步,发现自己确实在建造一座美丽的雕塑。

如果某些内容看起来特别困难,通常整夜盯着它毫无价值。休息一下,小睡片刻,吃点零食,向某人(或许是你的狗)解释你遇到的问题,然后带着新的视角重新面对它。我向你保证,一旦你学会了书中的编程概念,回看时会发现这一切其实非常简单而优雅,只是需要一些时间来吸收它。

1.1.13. 术语表

bug

程序中的错误。

central processing unit

任何计算机的核心。它运行我们编写的软件;也称为"CPU"或“处理器”。

compile

将用高级语言编写的程序一次性翻译为低级语言,以备后续执行。

high-level language

像 Python 这样的编程语言,旨在便于人类阅读和编写。

interactive mode

通过在提示符处键入命令和表达式来使用 Python 解释器的一种方式。

interpret

通过逐行翻译来执行用高级语言编写的程序。

low-level language

旨在便于计算机执行的编程语言;也称为“机器码”或“汇编语言”。

machine code

软件的最低级语言,即由中央处理单元 (CPU) 直接执行的语言。

main memory

存储程序和数据。主存会在断电时丢失其信息。

parse

检查程序并分析其语法结构。

portability

程序的一种属性,使其能够在多种类型的计算机上运行。

print function

一条使 Python 解释器在屏幕上显示值的指令。

problem solving

表述问题、寻找解决方案并表达该解决方案的过程。

program

指定计算的一组指令。

prompt

当程序显示消息并暂停以等待用户向程序输入某些内容时。

secondary memory

存储程序和数据,即使在断电后也能保留其信息。通常比主存慢。辅助存储器的示例包括磁盘驱动器和 USB 闪存盘中的闪存。

semantics

程序的含义。

semantic error

程序中导致其行为偏离程序员意图的错误。

source code

用高级语言编写的程序。

1.1.14. 练习

练习 1:计算机中辅助存储器的功能是什么?

a) 执行程序的所有计算和逻辑 | b) 通过互联网检索网页 | c) 长期存储信息,即使跨越电源周期 | d) 从用户获取输入

练习 2:什么是程序?

练习 3:编译器与解释器有何区别?

练习 4:以下哪项包含“机器代码”?

a) Python 解释器 | b) 键盘 | c) Python 源文件 | d) 文字处理文档

练习 5:以下代码有什么问题:

>>> primt 'Hello world!'
File "<stdin>", line 1
  primt 'Hello world!'
                     ^
SyntaxError: invalid syntax
>>>

练习 6:在以下 Python 语句执行完毕后,变量如 "x" 存储在计算机的哪个位置?

x = 123
a) 中央处理器 | b) 主存储器 | c) 辅助存储器 | d) 输入设备 | e) 输出设备

练习 7:以下程序将输出什么:

x = 43
x = x + 1
print(x)
a) 43 | b) 44 | c) x + 1 | d) 错误,因为数学上 x = x + 1 是不可能的

练习 8:用人类能力的例子解释以下内容:(1) 中央处理器,(2) 主存储器,(3) 辅助存储器,(4) 输入设备,和 (5) 输出设备。例如,“人类中央处理器的等价物是什么”?

练习 9:如何修复“语法错误”?


  1. http://xkcd.com/231/ ↩︎


如果您在本书中发现错误,欢迎使用 Github 发送修正。

   «  Chapter 0 Base Material   ::   目录   ::   2. PY4E - Python 为所有人  »

关闭窗口