用Python编程 笔记1

第一章 编程方法

The Way of The Program

本书的目的是教会你如何像一个计算机科学家一样思考。计算机科学家的思考方式结合了数学、工程学和自然科学的一些最好的特点。像数学家们一样,计算机科学家们使用规范化的语言(特别是计算语言)表示想法。像工程师一样,计算机科学家设计东西,将各个部件组合进系统内,并且评估各种可能的组合之间的利弊。像科学家一样,他们分析复杂系统的行为,提出猜想,并对其进行检测试预测。

对一个计算机科学家而言最重要技能是:解决问题(problem solving.)。解决问题意味着对问题进行表述的能力,对于解决方案进行创造性地思考能力以及清晰、准确地表达解决方法的能力。人们发现:学习编程的过程是人们练习问题解决能力地一个绝佳机会。这也是为什么这一章被称为“编程方法”的原因。


1.1 Python编程语言

你将学习的语言是Python。Python是一门高级语言(high-level language),你可能听过其他一些高级语言:C,C++,Perl或者Java。

你可能会根据“高级语言”这个名称推断出,也存在低级语言(low-level language),有时也称为“机器语言”(machine languages)或者“汇编语言”(assembly languages)。严格地说率而言,计算机只能执行用低级语言编写的程序。因此,使用高级语言编写的程序不得不在运行之前被转换。这种转换.需要一些时间,这是高级语言的一个细小的缺点。

但是高级语言的优势是巨大的。首先,使用高级语言编程更加容易。使用高级语言编写程序耗费的时间更短,代码将简短易读,也更可能是正确的。其次,高级语言具有移植性(portable),意味着这些程序可以在经过较小的修改或者无需改动就可以在不同种类的计算机上运行。低级语言编写的程序只能在一种计算机上运行,如果需要在其他种类计算机上运行则需要重新编写。

由于这些优点,几乎所有的程序都是使用高级语言编写的。低级语言只用于很少特定的应用。

有两种程序可以将高级语言处理成低级语言:解释器(interpreter)或者编译器(compiler)。解释器读取一个高级语言程序并且执行这个程序,即按照程序说的去做。解释器对程序一次一行地进行处理,并且在读取程序行和进行计算之间切换。

Think Like A Computer Scientist 1-1

编译器读取一个高级语言程序,在程序运行之前将程序全部翻译完。这种情况下的高级语言被称为源代码(source code),被翻译成的代码被称为对象代码(object code)或者可执行代码(executable code)。一旦程序被编译了,你将可以反复执行它而不需要再进行任何翻译。

Think Like A Computer Scientist 1-2

因为Python编写的程序都通过解释器来执行,所以Python是一种解释型语言。有两种方式使用解释器:命令行模式(command-line mode)和脚本模式(script mode)。在命令行模式中,你输入Python程序然后解释器输出结果。

这个例子的第一行是启动Python解释器的命令。接下来两行是解释器发出的信息。第三行以>>>开始,它是解释器用来表示解释器准备好了的提示符(prompt)。我们输入print 1+1,解释器返回2.

另外,你可以将程序写在一个文档中,使用解释器去执行文档中的内容。这样的文档被称为脚本(script)。例如:我们使用文本编辑器创建一个名为latoya.py的文档,其内容如下:

按照惯例,包含Python程序的文档以.py作为后缀。

执行这个程序,我们需要告诉解释器该脚本的名称:

在其他开发环境中,执行程序的具体细节可能不一样。此外,大多数程序都比这一个更有趣。

这本书中的大多数例子都是在命令行内执行的。在命令行上工作方便程序开发和测试,因为你可以输入程序并且立刻执行他们。一旦你的程序能够正常工作,你应该将其储存进一个脚本中去,这样之后你可以在未来执行或者修改脚本。


1.2 什么是程序?

程序是一系列指定如何执行计算(computation)的指令的序列。计算可以是数学计算,例如如何解一个方程组或者求多项式的根。就算也可以是符号计算(symbolic computation),例如查找并替换一个文档中的文字或者编译一个程序。

不同编程语言的细节看上去不同,但是一些基本的指令在几乎所有的语言中都会出现:

input:从键盘、文档或者其他一些设备获得数据。
output:在屏幕上显示数据或者将数据发送至其他设备或者发送至一个文档中。
math:执行基本的数学运算,如加法和乘法。
conditional execution:检查某些条件或者执行适当的语句序列。
repetition:重复执行某些动作,通常带有一些变化。

不论你信不信,这些几乎就是全部的基本指令了。你所使用过的每一个程序,无论它是多么的复杂,都是由一些多少与这些基本指令有些相像的指令所构成。因此,我们可以这样形容程序:程序是一个将大而复杂的任务不断分解成更小的子任务,直到这些子任务小到足以使用这些简单的指令实现的过程。

这可能有些含糊,但是我们稍后讨论算法(algorithms)的时候一定会回来继续这个话题。


1.3 什么是调试?

编程是一个复杂的过程,而且因为编程的过程是由人类完成的,编写的程序往往会导致错误。由于一些异想天开的原因,编程错误被叫做漏洞(bug)而跟踪并纠正这些漏洞的过程叫做调试(debugging)。

一个程序可能发生的错误有三类:语法错误(syntax error),运行时间错误(runtime error)和语义错误(semantic error)。区分这三种错误可以帮助我们更快地查出错误所在。

1.3.1 语法错误

只有在程序语法正确的情况下,Python才可以执行这个程序,否则的话,程序的执行过程将失败并且返回一个错误信息。语法指的是一个程序的结构以及有关这个结构的规则。例如:英语中一个句子必须以一个大写字母开头并且以一个句号结尾。句子”this sentence contain a syntax error.”含有一个语法错误(首字母未大写),这个句子“So does this one”也是(结尾未加句号)。

对绝大多数读者来说,少量的语法错误并不是一个要紧的问题,这是我们人在读e.e. cummings的诗歌时不会一边读着一边有错误信息喷涌而出的原因。Python则不是那么宽容。如果在你的程序中的任何地方有一处语法错误,Python都会输出一个错误信息并且退出,你将无法运行你的程序。在你编程生涯的最初几周时间里,你可能会花很多的时间去查找语法错误。不过,当你经验丰富起来后,你会更少地犯错误并且能够更快地找到错误。

1.3.2 运行时间错误

第二类错误是运行时间错误,这么叫的原因在于这些错误直到你运行程序的那一刻才会出现。运行时间错误也被叫做异常(exception),因为它通常意味着有些异常的事情发生了。

在最初几章的简单程序中你将很少遇到运行时间错误,过上一段时间之后你可能才会遇见。

1.3.3 语义错误

第三类错误是语义错误。如果你的程序中有一个语义错误,程序将能够成功运行,这意味着计算机将不会生成任何错误信息,但是程序将不能做它应该做的事,它将会做其他一些事情。具体来说,程序将做你告诉它要去做的事情。

问题在于,你所编写的程序并不是你想要编写的程序。你编写的程序的语义是错误的。要发现语义错误可能会非常棘手,因为它需要你反过来推算——在看到程序输出的结果之后试图理解程序做的是什么。

1.3.4 实验调试

通过学习编程你将获得的最终要的技能之一就是调试。虽然调试的过程可能会令人沮丧,但是调试是编程最需要智慧、最具有挑战和最有趣味的不封。

就某些方面而言,调试就像侦探工作。你将会面对各种线索,而你需要的是去推断,怎样的过程和事件可以导致你想要的结果。

调试就像一门实验科学。一旦你对什么地方出了错有了想法,你修改你的程序然后再次尝试。如果你的假设是正确的,你便可以预测修改之后的结果,你也就离一个可正确运作的程序更近了一步。如果你的假设是错误的,那么你便需要从新来过了。正如福尔摩斯指出的“当你排除了所有的不可能,无论剩下的是什么,不论多么地难以置信,它一定就是真相。”(柯南 道尔 《四签名》)

对一些人而言,编程和调试是同一件事。即,编程是对一个程序不断地调试,直到程序做你想要它做的事情的过程。这个想法是,你应该从一个具有一些功能的程序开始,通过对它进行小的修改,并且同时调试程序,这样你永远都有一个可以运作的程序。

例如,Linux是一个包含了无数行代码的操作系统,但是它在一开始只是Linus Torvalds用来探索Intel 80386芯片的一个简单程序。根据Larry Greenfield的书,“Linus的早期项目之一,是一个在打印AAAA和BBBB之间切换的程序。这个程序后来演变成了Linux。”(Linux用户指南Beta版1)

之后的章节里,我们将提出更多有关调试和编程实践的建议。


1.4 形式语言和自然语言

自然语言(natural language)是人们所说的语言,例如英语、西班牙语和法语。它们都不是由人设计的(尽管人们试图给这些语言加一些秩序);自然语言的演化是自然演化。

形式语言(formal language)是由人们为特定应用设计的语言。例如:数学家使用的符号是一种形式语言,它特别适合用来表示数字和符号之间的关系。化学家使用一种形式语言去表示分子的化学结构。最重要的是:

编程语言是被设计用来表达计算的形式语言
(Programming languages are formal languages that have been designed to express computations.)

形式语言往往有严格的语法规则。例如:3+3=6是一个语法正确的数学语句,但是3=+6$就不正确了。H2O是语一个法正确的化学名称2Zz则不正确。

语法规则有两种类型,记号(token)规则和结构(structure)规则。记号是语言的基本元素,如文字、数字和化学元素。3=+6$的问题是,$并不是一个合法的数学记号(至少据我们所知如此)。同样,2Zz不合法是因为没有元素以Zz作为缩写。

第二种类型的语法错误与一个语句的结构有关,也就是记号的排列方式。语句3=+6$在结构上是非法的,因为你不能将加号直接放在一个等号的后面。同样的分子式中下标应该在元素名的后面,而不是在前面。

作为一次练习,试着写出一个看上去结构正确而含有不可识别的记号的英语语句。然后再试着写出一个所含记号均有效但是含有无效结构的句子。

当你读一个英语语句或者一个形式语言的语句时,你需要弄清楚语句的结构(尽管对于自然语言中,你只在下意识里这么做)。这个过程称为语法分析(parsing)。

例如,当你听到”另一只鞋子掉了下来“这句话,你明白”另一只鞋子“是主语,而”掉了下来“是一个谓语。一旦你对一个句子进行语法分析,你便可以弄清楚这个句子的意思,即句子的语义。假使你知道鞋子是什么并且知道掉了下来是什么意思,你就能明白这句话的一般含义。

虽然形式语言和自然语言之间有许多共同点——记号、结构、语法和语义——但是他们之间还有很多不同点:

歧义(ambiguity):自然语言充满歧义,人们利上下文线索和其他信息来处理自然语言。形式语言被设计成彻底地或者尽可能地明确,这意味着任何一个语句都只有一个明确的含义,不管语境如何。

冗余(redundancy):为了弥补歧义和减少误解,自然语言采用了大量的冗余。因此,自然语言往往更加冗长。形式语言则很少有冗余并且更加简明。

无修饰(literalness):自然语言充满了习惯用语和隐喻。如果我说,“另一只鞋掉了下来”,实际上有可能没有鞋也没有什么东西掉落。形式语言里,语句说了什么就是意味着什么。

我们每个人都说着自然语言长大,大家往往在适应形式语言时会经历一些困难。在一些方面,形式语言和自然语言之间的区别有些像诗歌和散文之间的区别,具体地:

诗歌:词语的作用不仅仅在于他们的含义,还在于他们的发音,整首诗歌整体上产生一个效果或者情绪反应。歧义不仅常见而且往往是刻意而为。

散文:文字的字面意思更加重要,结构对文章的含义贡献也更多。散文比诗歌更经得起分析,但是也常常模棱两可。

程序:一个计算机程序的含义是字面的,是明确的,并且可以通过分析记号和结构来完全理解。

这里是一些有关阅读程序(包括其他形式语言)的建议。首先,请记住,形式语言比自然语言更加压缩(dense),因此需要更多的时间才能读懂。此外,结构非常重要,所以从上倒下,从左到右地去读程序,通常不是一个好主意。相反地,学会在头脑中对程序进行语法分析,找出记号,解析结构。最后,细节很重要。像是拼写错误或者错误的标点符号这些小问题,在自然语言中你可以不太在意他们,但是在形式语言中他们意义重大。


1.5 第一个程序

按照传统,使用一门新语言编写的第一个程序叫做“你好,世界!”(“Hello, World!”),这么叫是因为这个程序所做的事情就只是显示“Hello, World!”在Python中,这个程序看上去是这样的:

按照传统,使用一门新语言编写的第一个程序叫做“你好,世界!”(“Hello, World!”),这么叫是因为这个程序所做的事情就只是显示“Hello, World!”在Python中,这个程序看上去是这样的:

上面是一个打印语句(print statement)的例子,实际上它并没有在纸上打印任何东西,它的作用是在屏幕上显示一个值(value)。在上面的例子里,输出的是这些词语:

Hello, World!

在程序中,使用引号将值的开头和结尾标记了起来,它们没有出现在结果中。

有些人凭借”Hello, World!”程序的简明程度来判断一门编程语言的品质。根据这个标准,Python已经是尽可能地好了。


第二章 变量,表示法和语句

Variables, Expressions and Statements

2.1 值和类型

就像一个字母或者一个数字一样,在程序中,(value)是被程序操作的基本东西之一。目前我们所见过的值有2(当我们计算1+1时获得的值)以及’Hello, World!’。

这两个值分属于不同的类型(types):2是一个整数,而’Hello, World!’是一个字符串(string)。字符串因为含有一“串”的字符而得名。你(以及解释器)可以识别字符串,因为它们被包含在引号内。

打印语句同样也适用于整数。

如果你不知道一个值的类型是什么,解释器可以告诉你。

不出意料,字符串属于str类型,整数属于int类型。带有小数点的数字属于一个叫float的类型,因为这些数字使用一种叫做浮点(floating-point)的方式来表示。

那么像’17′和’3.2′这样的值是什么类型的?它们看起来像数字,但是他们被包含在引号内,就像字符串一样。

它们的类型是字符串。

当你键入以个较大的整数时,你可能会想使用逗号将数字三位三位地隔开,就像1,000,000。而这在Python中不是一个合法的整数,但是却是一个合法的表达式。

嗯,结果完全不是我们所预料的那样!Python将1,000,000解释成一个含有三个整数的列表(list),这三个整数之间用逗号分隔开,打印这个列表将会连续打印列表内的三个整数。这是我们见到的第一个语义错误的例子:代码可以正常运行并且没有产生错误信息,但是它所做的事情不是我们希望它做的。


2.2 变量

一门编程语言最强大的功能之一就是可以操作变量(variable)。变量就是一个名称,该名称指向一个值。

赋值语句(assignment statement)可以创建新的变量并且赋予他们值。

上例进行了三次赋值。第一次赋值是将字符串“What’s up, Doc?”赋值给变量message。第二次赋值是将整数17赋值给变量n。第三次赋值是将浮点数3.14159赋值给变量pi.

注意,第一次赋值语句中使用双引号将一个字符串包含在内。一般情况下,单引号和双引号的效果一样,但是如果字符串内含有单引号(或者撇号,同样的字符)时,你必须使用双引号。

一个通常用来在纸上表示变量的方法是:写下变量的名称和值,然后用箭头将变量的名字指向值。这样的图被称为状态图(state diagram),因为它显示了每一个变量的状态(将其试想为变量的心理状态)。下图显示的是之前赋值语句的结果。

state diagram

打印语句同样适用于变量。

在每一种情况下,结果都是变量所指向的值。变量也有类型。我们同样可以问解释器变量的类型是什么。

变量的类型就是它所指向的值的类型。


2.3 变量名和关键字

在给变量命名的时候程序员一般会选择含有意义的名字,这些变量的名字表明了变量的用处。

变量名可以是任意长度的,它们可以同时包含字母和数字,但是必须以字母开头。虽然使用大写字母是符合规则的,但是按照惯例我们不使用大写。如果你需要使用大写字母,记住大小写是区分的,Bruce和bruce是不同的变量。

下划线字符_可以出现在变量名中。它常被用在含有多个单词的名称中,例如:my name_or_price_of_tea_in_china。

如果你给变量一个不合法的名字,你会得到一个语法错误提示:

76trombones是非法的变量名,因为它不是以字母开头的。more$是非法的变量名,因为它含有一个非法字符美元符号。但是,class作为变量名为什么是不合法的?

原来,class是Python的关键字(keywords)之一。关键字定义了编程语言的规则和结构,它们不能够被用来作为变量名。

Python有29个关键字

and def exec if not return
assert del finally import or try
break elif for in pass while
class else from is print yield
continue except golbal lambda raise

你可能会想要把这个列表放在手边。如果解释器提示,你的程序中变量名有问题,你不知道是怎么回事的话,查看一下是否有列表上的关键字被用作了变量名。


2.4 语句

语句是一种Python的解释器可以执行的指令。我们已经见过了两种语句:打印和赋值。

当你在命令行键入一个语句的时候,Python执行这个语句并且在有结果的情况下显示其结果。打印语句的结果是一个值。赋值语句将不会产生结果。

一个脚本通常含有一系列的语句。如果有不止一条语句,结果会按照语句执行·的顺序依次显示。

例如脚本:

产生的输出结果:

赋值语句不产生结果。


2.5 表达式求值

表达式是值、变量和运算符的组合。

如果你在命令行键入一个表达式,解释器将对其求值,并显示结果。

虽然表达式包含值、变量和运算符,但不是所有的表达式都包含这些元素。一个值就可以被认为是一个表达式,一个变量也是如此。

可能容易混淆的是,表达式的求值与结果的打印并不是相同的事。

当Python解释器显示对一个表达式所求的值时,它使用的格式和你用来输入一个值的格式相同。以计算结果是字符串为例,这意味着所求的值将包含引号。

但是如果你使用打印语句打印这个结果,Python将显示不带引号的字符串的内容。

在一个脚本中,一个表达式本身即使一个合法的语句,但是它将不会做任何事情。例如脚本:

上述脚本不产生任何输出。你对它进行怎样的改变才可以使其显示这四个表达式所求的值呢?


2.6 运算符和运算项

运算符是用来表示像加法、乘法这样的运算的特殊符号。运算符使用的值被称为运算项

下面都是一些意义或多或少清晰的合法表达式:

20+32 hhour-1 hour*60+minute minute/60 5**2 (5+9)*(15-7)

+ – 和/符号,以及使用括号进行分组,这些在数学中和在Python中都是一样意义的。星号(*)是乘法的符号,**则是幂运算符号。

当一个变量名出现在运算项的位置的时候,在运算进行之前,将使用该变量的值代替运算项的值。

加法、减法、乘法和幂运算都像你所期待的那样进行运算,但是你可能会对除法的结果感到惊讶。下面的运算含有一个你所意想不到的结果:

变量minute的值是59,按照传统算术方法,59除以60的结果是0.98333,而不是0。这样差异的原意是:Python执行的是整除

当两个运算项都是整数的时候,除法的结果必须同样是整数,按照惯例,即使结果与下一个整数非常近似,整除也总是去除尾数。

这个问题的一个可行的解决方案是计算百分比,而不是计算一个分数。

虽然结果仍然是去除了尾数,但是至少现在但是是大约正确的。另一种方法是使用浮点数除法,我们将在第三章讨论。


2.7 运算的顺序

当一个表达式里出现多个运算符时,求值的顺序取决于运算符优先级规则(rules of precedence)。Python的数学运算符采用与数学中相同的优先级。PEMDAS这个缩写是一种帮助记忆运算顺序的有效方法。(注:PEMDAS可以采用Purple Elephants Marching Down A Street以及其他一些缩写为PEMDAS的句子来帮助记忆)

括号(Parentheses)具有最高的优先级,可以被用来强制一个表达式按照你想要的顺序来求值。由于括号中的表达式被优先求值,2 * (3-1)的结果是4而(1+1)**(5-2) 的结果是8。你也可以用括号来使一个表达式更容易被读懂,就像(minute * 100)/ 60中,虽然加不加括号并不影响结果,但是使其更容易读懂。

幂运算(Exponentiation)拥有第二高的优先级,所以2**1+1的结果是3而不是4,3*1**3的结果是3而不是27。

乘除加减(Multiplication Division Addition and Subtraction)乘法和除法有相同的优先级且高于加法和减法。加法和减法也具有相同的优先级。因此表达式2*3-1返回结果5而不是4,2/3-1返回结果是-1而不是1(整数除法中,2/3的结果是0)

具有相同优先级的运算符按照从左往右的顺序依次进行求值。在表达式minute*100/60中乘法先进行,返回结果5900/60,进一步返会结果98.如果运算符依照从右往左的顺序进行求值,结果将是59*1,即59,这是错误的。


2.8 字符串的运算

在一般情况下,你不能对字符串进行数学运算,即使是看起来是数字的字符串也是如此。以下是一些非法的例子(假使变量message所指向的值为字符串类型):

message-1 ’Hello’/123 message*’Hello’ ’15’+2

有趣的是,+运算符可以对字符串进行运算,但它所做的运算可能不是你所期望的那样。对于字符串,+运算符表示着串联(concatenation),串联意味着将运算项通过首尾相连的方式连接起来。

这个程序的输出是banana nut bread。单词nut前的这个空格也是字符串的一部分,为了使被串联的两个字符串之间用空格隔开,这是必要的。

*运算符同样也可以对字符串进行运算;它执行的效果是重复。例如:’Fun’*3的结果是’FunFunFun’。一个运算项必须是一个字符串,另一个运算项则必须是一个整数。

一方面,这种对于字符串使用+和*运算符的结果,与加法以及乘法是类似的。就像4*3的结果等价于4+4+4一样,我们对于’Fun’*3所做的运算的期望是’Fun’+'Fun’+'Fun’,并且实际上也是如此。另一方面,字符串的串联和重复和整数的加法、乘法有着重要的区别。你能够想到一个加法和乘法所具备的而字符串串联和重复所不具备的性质么?


2.9 组合

目前为止,我们已经分别单独地见过了一个程序的这些元素:变量、表达式和语句,我们还没有讨论如何将它们结合起来。

编程语言最有用的功能之一就是他们将小的构建模块进行组合(compose)的能力。例如:我们知道如何累加数字并且我们知道如何打印,结果是我们可以同时做这两件事:

实际上,加法必须在打印之前进行,实际上这两个行为不是同时发生的。关键在于,任何一个包含数字、字符串和变量的表达式都可以被使用在一条打印语句里面。你已经见过了这样一例子:

你也可以把任意表达式放在一个赋值语句的右边:

这种可能性现在看上去可能并不那么令人印象深刻,但是以后你会看到其他通过使用组合使得复杂计算的表达更加简洁明了的例子。

警告:你可以在什么地方使用特定表达式是有限制的。例如:一个赋值语句的左边必须是变量名而不是表达式。因此下面是非法的:minute + 1  = hour。


2.10 注释

当程序变得更大且更加复杂的时候,它们也变得更加难以读懂。形式语言是浓缩的,通常难以通过看一段代码来弄明白它是做什么的以及为什么这么做。

出于这个原因,通过对你的程序添加注解的方式,使用自然语言来解释程序是做什么的,是一个好主意。这些注解被称为注释(comment),它们使用#符号来标记:

这种情况下,注释本身占用一行。你也可以把注释放在一行的结尾处:

#号开始到这一行的末尾的一切都被忽略了,即这一行的内容对程序没有任何影响。这里的注释信息旨在给程序员和未来可能会使用这个代码的程序员看。在这种情况下,注释提醒读者有关曾经令我们惊讶的整除结果。

这样的注释在你使用整除运算符//时,就变得不是那么必要了。它与整除符号/具有相同的效果,但是它表示整除是刻意的。

整除运算符就像这样一个注释:“我知道这是一个整除,并且我希望它是一个整除。”


2.11 术语

值(value):可以被存储在一个变量中或者可以被一个表达式计算的一个数字或者一个字符串(或者其他以后将提到的一些东西)。

类型(type):一个值的类型决定了它可以被如何用于表达式中。目前为止,你已经见过的类型有:整数(类型为int),浮点数(类型为float),以及字符串(类型string)。

浮点(floating-point):一种表示带有小数部分数字的格式。

变量(variable):一个指向一个值的名称。

语句(statement):一段表示一个命令或者行为的代码。目前你见过的语句是赋值语句和打印语句。

赋值(assignment):一个将一个值分配给一个变量的语句。

状态图(state diagram):用来表示一组变量以及它们所指向的值的图形表示法。

关键字(keyword):被编译器用来分析程序的保留字;你不可以使用如if,def以及while这样的关键字作为变量名。

运算符(operator):一种用来表示像加法、乘法或者字符串串联这样的简单计算的特殊符号。

运算项(operand):一个运算符号进行运算的值之一。

表达式(expression):变量、运算符和值的组合,表达一个单一的结果值。

求值(evaluate):通过按照顺序进行运算来简化一个表达式至一个单一值。

整除(integer division):整除运算符使用一个整数除以另一个整数并且得到一个整数结果。整除得到的只是分子被分母所处之后的整数部分,不计任何剩余部分。

优先级规则(rules of precedence):对包含多个运算符和运算项的表达式的求值顺序进行调节的规则集。

串联(concatenate):将两个运算项头尾相连。

组合(composition):将简单的表达式和语句结合,构成语句和表达式的复合,从而简明地表达复杂计算的能力。

注释(comment):一个程序中旨在给其他程序员(或者其他阅读源代码的人)所看的信息,注释对于程序的执行没有影响。


第三章 函数

3.1 函数调用

>>> type(“32″)
<type ‘str’>

这里的type就是一个函数(function),函数调用的实际参数(argument)必须在括号内。函数的结果叫做返回值(return value)

相对于打印结果我们将函数的结果赋予一个变量:

>>> betty = type(“32″)
>>> print betty
<type ‘str’>

>>> id(3)
134882108

>>> betty = 3
>>> id(betty)
134882108

每一个值都具有一个id,这个数字代表着值在内存中的位置。变量的id就是变量所代表的值的位置。

3.2 类型转换(Type conversion)

Python提供一些将值从一种类型转化成另一种的函数。
一些例子:

>>> int(“32″)
32

>>> int(“Hello”)
ValueError: invalid literal for int():Hello

>>> int(3.99999)
3

>>> str(3.14149)
’3.14149′

3.3 类型强制(Type coercion)

应为整数除以整数返回的结果是整数所以

>>> minute = 59
>>> minute / 60
0

我们可以采取的方法:

采用类型转换:

>>> minute = 59
>>> float(minute) / 60
0.983333333333

或者采用类型强制

>>> minute = 59
>>> minute / 60.0
0.983333333333

Python中的除法中的除号两边只要有一边的运算对象是浮点类型,那么结果就被强制为浮点类型。

3.4数学函数(Math functions)

Python包含一个数学模块(module)提供很多常见的数学函数。
如果我们需要使用这个模块,我们必须引入这个模块。

>>> import math

要调用一个函数,我们需要指明模块和函数的名称,用’.'号隔开,这种方法又叫做圆点记法(dot notation)

>>> degrees = 45
>>> angle = degrees * 2 *math.pi / 360.0
>>>math.sin(angle)
0.707106781187

pi也是math模组内置的

3.5组合(composition)

Python中的函数是可以组合的。一个函数可以成为另一函数的一部分

>>> x = math.cos(angle + math.pi/2)

>>> x = math.exp(math.log(10.0))

3.6新增函数

函数是一系列事先规定好的语句,用来进行想要的运算。(a function is a named sequence of statements that performs a desired operation.)这个运算在函数定义中被定义。

定义一个新函数的语法格式为:

def NAME(LIST OF PARAMETERS);
    STATEMENTS

函数名可以是Python关键词以外的任何名字,形式参数(parameters)不是必须的。

def newLine():
    print

自定义新函数的调用语法和系统自带函数的调用方法一样:

print “First Line.”
newLine()
Print “Second Line.”

输出结果为:

Frist Line.

Second Line.

函数定义内的每一条语句都需要开头空格2格,我们可以在函数定义内调用已有的函数:

def threeLine();
    newLine()
    newLine()
    newLine()

3.7定义和使用(Definition and use)

函数的定义也和其他声明一样需要被执行,所以一个函数一定要在被调用之前定义过才可以使用。

3.8执行流(Flow of execution)

正常情况下程序的执行是从上到下从左到右依次执行的。每当一个函数被调用的时候执行流跳转到调用函数的第一行依次执行下去,当函数被执行完后,再跳回调用函数前的所在行。当我们读程序的时候,不要一行一行读程序,而是遵循着程序的执行流读程序。

3.9形式参数和实际参数(parameters and arguments)

函数定义的时候有的时候需要实际参数,实际参数的值用来控制函数如何完成它的工作。在函数内,变量获得的值为形式参数。

def printTwice(bruce);
    print bruce, bruce

>>> printTwice(‘Spam’)
Spam Spam

‘Spam’的值被赋予printTwice函数里的变量bruce,然后执行函数内的打印两次bruce的命令。

>>> printTwice(’Spam’*4)
SpamSpamSpamSpam SpamSpamSpamSpam

‘Spam’*4会先被运算,运算的结果被赋予函数内的变量bruce。

如果函数改为:

def printTwice(bruce);
    print ‘Spam Spam’

>>> printTwice(bruce);
Spam Spam

除了实际的值可以作为形式参数以外,变量也可以被用来作为形式参数。

>>> michael = ’Eric, the half a bee.’
>>> printTwice(michael)
Eric, the half a bee. Eric, the half a bee.

3.10 变量和形式参数都是局部的(Variables and parameters are local)

形式参数这个变量是只存在于函数内的局部变量。

上例中如果我们运行

>>> print bruce

则返回

NameError: bruce

3.11栈图(Stack diagrams)

栈图可以用来帮助记忆、追踪不同变量的值

例图如下:

stack_diagram

栈图要体现执行流的顺序,main调用catTwice,而catTwice内调用printTwice

3.12含有结果的函数(Functions with results)

有些函数会返回结果,有些函数执行一些命令但是不返还结果。

How to Think Like a Computer Scientist

How to Think Like a Computer Scientist

Learning with Python

by Allen Downey, Jeff Elkner and Chris Meyers.

PDF Version : Link

Leave a Reply

Your email address will not be published. Required fields are marked *