Python入门教程

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

运行环境
1. 运行环境

要用python写程序,你必须先安装一个python的解释器。它可以存在于大多数平台(包括Macintosh、Unix和Windows)。更多与此有关的信息可以在python的网站上找到。你还应该有一个文本编辑器(象emacs、notepad或者类似的东西)。

编程是什么?
2. 编程是什么?

为计算机写程序其实就是给它一系列的指令告诉它去做什么。计算机程序在某些方面就象是菜谱,指导我们如何做菜的那种。例如[1]:

假日火腿沙拉

原料:

腌泡汁:
1/4杯酸橙汁
1/4杯低钠大豆酱油
1/4杯水
1大汤匙植物油
3/4茶匙小茴香
1/2茶匙牛至
1/4茶匙热胡椒粉
2片丁香、大蒜,捣碎

沙拉:
1份(12盎司)罐装少钠午餐肉火腿切成条状
1个洋葱,切片
胡椒粉,切好的生菜
12个樱桃西红柿,切半

方法:

把腌泡汁装在有合适盖子的广口瓶里摇匀。用塑料袋装上火腿,泼上腌泡汁,封住袋口。在电冰箱里腌制30分钟。从塑料袋里取出火腿;准备2大汤匙腌泡汁,在煮锅里煮一下。加上火腿、洋葱、绿色的胡椒。烧3到4分钟直到火腿熟了为止……

当然,没有一台计算机会懂这个……而且即便是懂,大多数计算机也不可能烧制出一份沙拉。那么,我们该如何让这些变得对计算机来说更为友好一些呢?从根本上说依赖于两点:首先,我们必须以计算机可以理解的方式与之交流;其次还要和它谈论它能够做到的事情。

第一点意味着我们必须使用一种语言--一种已经为之准备好了解释器的程序设计语言,第二点意味着我们不能期望计算机为我们做一份沙拉--但是我们可以让它做数字累加或者在屏幕上打印东西之类的事情。

Hello……
3. Hello……

程序设计教程有一个传统,通常以在屏幕上打印“Hello, world!”这样的程序做为开始。对python来说,这非常简单:


print "Hello, world!"


它从根本上说很象上面的菜谱(尽管要短得多!)。它告诉计算机做什么:打印“Hello, world!”。如果让它打印更多的废话该怎么做呢?很简单:


print "Hello, world!"
print "Goodbye, world!"


不比上一个难,是不是?但是不怎么有趣……我们希望它可以处理更多的元素,就象沙拉菜谱那样。那么,我们都有哪些元素呢?首先,有字符串,象“Hello, world!”,除此之外还有数字。假设我们打算让计算机为我们计算矩形的面积。我们可以给它如下的菜谱:


# The Area of a Rectangle

# Ingredients:

width = 20
height = 30

# Instructions:

area = width * height
print area


你大概可以看出它同火腿沙拉菜谱的相似性(尽管有些细微的差别)。但它是如何工作的呢?

首先,以#开始的行叫做注释事实上会被计算机忽略。然而插入象这样小段的注释对于增强你程序的可读性来说是很重要的。

接下来,看起来象 foo = bar 这样的行叫做赋值。对于 width = 20 这样的情况来说就是告诉计算机从这里开始width就代表20了。它还意味着一个名字为“width”的变量从此被创建了(如果它先前已经存在,那么会被重新覆盖)。所以,我们以后使用这个变量的时候,计算机就知道了它的值。因此,

width * height

本质上同

20 * 30

一样会计算出600这个结果,然后赋给名称为“area”的变量。程序的最后一句在屏幕上打印出变量“area”的值,所以你看到这个程序运行的最终结果仅仅是

600

注意:在某些程序设计语言中,你必须在程序开始的时候告诉计算机你将会用到哪些变量(就象沙拉中的元素)--而python足够聪明,所以你可以根据需要随时创建。

反馈
4. 反馈

现在,你可以执行一些简单,或者再复杂一点的计算了。比方说,你或许打算写一段程序来计算圆形的面积而不是矩形的:


radius = 30

print radius * radius * 3.14



然而,这事实上并不比计算矩形面积的那个程序更有意思。至少在我看来是这样。它有些僵硬。如果我们看到半径为31的圆该怎么办?怎样让计算机知道?这有点象沙拉菜谱中的:“烧3到4分钟直到火腿熟了为止。”要知道何时烧熟,我们必须检查。我们需要反馈,或者提示。计算机如何知道我们圆形的半径?同样需要输入资料……我们可以做的是告诉计算机半径是多少:


radius = input("What is the radius?")
print radius * radius * 3.14



现在程序变得漂亮一些了……input是个被称为函数的东西。(很快你将学习创建你自己的函数。而input是python内建的函数。)仅仅写下

input

什么也不会做……你必须在它的后面放上一对括号。所以input()可以工作--它会简单的要求用户输入半径的长度。而上面的那个版本对用户来说也许更友好一些,因为它首先打印出了一个问题。当我们将诸如提问字符串“What is the radius?”之类的东西放在函数调用的括号中时,这个过程被称为函数的参数传递。括号中的内容被称为参数。在上个例子中我们传递了一个提问作为参数以便input知道在获得答案前应该先打印什么。

但是获得的答案如何到达radius变量呢?函数input,调用时,会返回一个值(象许多其它函数一样)。你不一定非要使用这个值,但象我们这种情况,我们要使用它。这样,下面这两个表达式有着很大的差别:


foo = input
bar = input()


foo现在包含input函数本身(所以它事实上可以象foo("What is

your age?")这样使用;这被称为动态函数调用)而bar包含用户键入的值。


流程
5. 流程

现在我们可以编写程序执行简单的任务(运算和打印)并且可以获得用户输入了。这很有用,但仍然局限在按顺序执行命令,也就是说--它们必须按照事先安排好的顺序执行。大多数火腿沙拉菜谱是象这样顺序或者线性叙述的。但是如果我们打算让计算机检查沙拉是否烧好该怎样告诉它呢?如果烧好了,那么应该从烘箱里把它取出来--否则的话,应该接着让它烧更长一段时间什么的。我们如何表达这个?

我们想做的,其实是控制程序的流程。它可以从两个方向执行--要么拿开火腿,要不继续让它留在烘箱里。我们可以选择,条件是它是否烧好。这被称为条件执行。我们可以这样写:


temperature = input("What is the temperature of the spam?")

if temperature >; 50:
print "The salad is properly cooked."
else:
print "Cook the salad some more."



意思很明显:如果温度超过50(摄氏度),那么打印出信息告诉用户烧好了,否则,告诉用户再烧制一段时间。

注意:缩进在python中很重要。条件执行(还有循环执行以及函数定义--见后面)中的语句块必须被缩进(而且要缩进同等数量的空格;一个键相当于8个空格)以便解释器可以知道它们从哪里开始到哪里结束。这同时也使程序变得更加可读。

让我们回到先前的面积计算问题。能看出来这段程序做什么吗?


# Area calculation program

print "Welcome to the Area calculation program"
print "---------------------------------------"
print

# Print out the menu:
print "Please select a shape:"
print "1 Rectangle"
print "2 Circle"

#Get the user's choice:
shape = input(">; ")

#Calculate the area:
if shape == 1:
height = input("Please enter the height: ")
width = input("Please enter the width: ")
area = height *width
print "The area is ", area
else:
radius = input("Please enter the radius: ")
area = 3.14 * (radius**2)
print "The area is ", area



这个例子中的新东西:
1. 只使用print本身将打印出一个空行
2. ==检查两个值是否相等,与=不同,后者把表达式右侧的值赋给左侧的变量。这是一个非常重要的差别!
3. **是python的幂运算符--因此半径的平方被写成radius**2
4. print能够打印出不止一个东西。只要用逗号把它们分开就可以了。(它们在输出时会用单个空格分开。)

这个程序很简单:它要一个数字,告诉它用户打算让它计算矩形或是圆形的面积。然后,使用一个if语句(条件执行)来决定应当执行哪个语句块计算面积。这两个语句块同先前面积计算例子中使用的语句

块本质上是一样的。留意注释是如何使代码变得更加可读的。编程的第一条戒律就是:“你应当注释!”无论如何--它都是一个应该养成的好习惯。

练习1:

扩展上面的程序使它包括正方形面积的计算,用户只要输入它一条边的长度就可以了。做这个练习之前你需要了解一件事:如果你有两个以上的选择,你可以象这样写:


if foo == 1:
# Do something...
elif foo == 2:
# Do something else...
elif foo == 3:
# If all else fails...



这里的elif是意思为“else if”的神秘代码:)。所以,如foo等于1,做某件事;否则,如果foo等于2,那么做另外的一些事,等等。你也可以在程序中加入其它的选项--象三角形以及任意多边形。随你的便。


循环
6. 循环

顺序执行和条件执行仅仅是程序设计三个基本语句块架构方式中的两个。第三个则是循环执行。在上个段落中我假设了一种情况,检查火腿是否烧好,但很明显它并不适用。如果下次检查时火腿仍然没烧好该怎么办?我们怎么知道需要检查多少次?事实上,我们不知道。而且我们也没必要知道。我们可以要求计算机持续检查直到烧好了为止。怎么表达这个?你猜到了--我们使用循环,或者说是重复执行。

python有两种循环类型:while循环和for循环。for循环大概是最简单的。举个例子:


for food in "spam", "eggs", "tomatoes":
print "I love", food



它的意思是:对于列表"spam", "eggs", "tomatoes"中的每个元素,都打印出你喜欢它。循环中的语句块为每个元素执行一次,而且每次执行,当前的元素都被赋给变量food(在这个例子中)。另外一个例子:


for number in range(1, 100):
print "Hello, world!"
print "Just", 100 - number, "more to go..."

print "Hello, world"
print "That was the last one... Phew!"


函数range返回给定范围的数字列表(包括第一个数字,不包括最后一个……这个例子中是[1……99])。所以,这样解释它:

循环体为1(包括)到100(不包括)之间的数字每个执行一次。(哪个是循环体以及随后的表达式事实上做什么留下来做为练习。)

但这对我们的烧菜问题并没有实质的帮助。如果我们打算检查火腿一百次,那么这是个很好的解决方案;但是我们不知道这是否够--或者太多了。我们只是希望它在温度达不到(或者,直到它足够热--大致某个状态)的时候持续检查。所以,我们使用while:


# Spam-cooking program

# Fetch the function sleep
from time import sleep

print "Please start cooking the spam. (I'll be back in 3 minutes.)"

# Wait for 3 minutes (that is, 3*60 seconds)...
sleep(180)

print "I'm baaack :)"

# How hot

is hot enough?
hot_enough = 50

temperature = input("How hot is the spam?")
while temperature < hot_enouth:
print "Not hot enough... Cook it a bit more..."
sleep(30)
temperature = input("OK, How hot is it now?")

print "It's hot enough - You're done!"


这个例子中的新东西……

1. 有些有用的函数被存储在模块中而且可以被导入。此例中我们从python自带的time模块中导入了函数sleep(它休止给定的多少秒的时间)。(做你自己的模块当然也是可能的……)

练习2:

写一个程序,持续从用户获得数据然后相加,直到它们的和为100。再写一个程序,从用户那里获得100个数据,打印出它们的和。

Bigger Programs - Abstraction

如果想知道一本书的大致内容,你不会翻遍所有的页--你只是看看目录,是不是?它会列出书的主要内容。现在--想像写一本菜谱。许多菜谱,像“奶油火腿通心面”和“瑞士火腿馅饼”很可能包含相同的东西,比如火腿,在这种情况下--你肯定不会打算在每个菜谱里都重复叙述如何制作火腿。(好了……你事实上可能不做火腿……但是为了做例子,请忍受一下:))。你会把制作火腿的菜谱单独放在一个章节,而仅仅在其它章节里引用它。这样--代替在每个菜谱里都完整的描述,你只要引用章节的名称就可以了。在计算机编程中这被称为抽象化。

我们是不是已经象这样运行了某些东西?是的。我们没有详细的告诉计算机如何从用户那里获得一个答案(好了--我们没有真的这样做……同样地……我们也没有真正的在做火腿:))而是简单的使用了input--一个函数来代替。我们事实上可以构造我们自己的函数,来应用于这种类型的抽象化中。

假设我们希望找到小于给定正数的最大整数。例如,给定2.7,这个数应当是2。这往往被称为给定数的“底线(floor)”。(这事实上可以用python的内建函数int来处理,但是,请再次忍受我拿它作例子……)我们该怎样做?一个简单的解决办法是从0开始试每一个可能的数:


number = input("What is the number?")

floor = 0
while floor <= number:
floor = floor + 1
floor = floor - 1

print "The floor of ", number, "is ", floor


注意当floor不再小于(或者等于)给定数时循环结束了;我们加了太多1给它。因此我们必须为它减去1。如果我们希望把它应用于完整的数学运算该怎么办呢?我们不得不为求每个数的基数("floor"-ing)而写一次完整的循环。这很不舒服……你可能猜到了我们代之以什么:把它放在我们自己的函数中,命名为“floor”:


def floor(number):
result = 0
while result <= number:
result = result + 1
resul

t = result - 1
return result


这个例子中的新东西……

1. 函数用关键字def定义,函数名紧随其后并且要用括号把需要的参数括起来。
2. 如果要求函数返回一个值,要使用关键字return来处理(它同时也自动结束函数定义)。

定义了函数之后,我们可以象这样使用它:


x = 2.7
y = floor(2.7)


执行后,y的值应该是2。定义拥有多个参数的函数也是可以的:



def sum(x, y):
return x + y



练习3

写一个函数,用欧几里德方法寻找两个数的一个共同因数。工作过程是这样的:

1. 假设两个数,a和b,a大于b
2. 重复以下步骤直到b变成0:
1. a变为b的值
2. b变成没有改变值之前的a除以没有改变值之前的b的余数
3. 返回a的最后一个值

提示:

* 使用a和b作为函数的参数
* 简单的设定a大于b
* x除以z的余数用表达式 x % z 来计算
* 两个变量可以象这样一起赋值:x, y = y, y+1。这里x被赋以值y(这意味着,y的值此前已经指定)而且y被递增了1。


深入函数
7. 深入函数

上面的练习怎么做?难吗?还不太清楚函数?别担心--我还没完成我的话题呢。

我们构建函数时使用的萃取方法称为过程抽象,许多编程语言把关键字过程同函数一样使用。事实上,这两个概念是不一样的,但是在python中它们都被称为函数(因为它们或多或少以同样的方式定义和使用)。

函数和过程(在其它语言中)的区别在哪里呢?嗯--就像你在前面的段落里看到的那样,函数可以返回一个值。区别就是过程并不返回这样的值。许多时候,用这种方法把函数划分为两种类型--返回值的和不返回值的--是很有用的。

不返回值的函数(过程)可以用作子程序或例行程序。我们调用这些函数,它们制造某些原料,就象泡沫鲜奶之类的。我们可以在很多地方使用这个函数而不需要重写它的代码(这被称为代码再利用--以后你还会知道,它意义不仅仅在这里)。

这样的函数(或过程)的另一个有用性体现在--它改变了环境(例如,把糖和奶油混在一起搅拌,它们的整个外部状态就变化了)让我们看个例子:

def hello(who):
print "Hello, ", who

hello("world")
# Prints out "Hello, world"



打印出内容是它一方面的作用,因为这是这个函数唯一需要做的事,它其实是一个典型的所谓过程。但是……它事实上没有改变它的运行环境,是不是?它怎样才能改变呢?让我们试一下:

# The *wrong* way of doing it
age = 0

def setAge(a):
age = a

setAge(100)
print age
# Prints "0"



错在哪儿?错在函数setAge创建了它自己的也被命名为age的局部变量,

它只在setAge函数内部可用。那如何才可以避免出现这个问题呢?我们可以使用全局变量。

注意:全局变量在python中不常用。它们容易引起不好的代码组织结构,被称为意大利面代码。我这里使用它们是为了引出更复杂一点的技术问题--如果你可以请尽量避免使用它们。

第 8 章
通过告诉解释器一个变量是全局的(用象global age这样的表达式做),我们事实上
告诉了它在函数之外使用这个变量,而不是重新创建一个新的局部变量。(所以,和局部
相反它是全局的。)因此上面的程序可以象这样重写:

# The correct, but not-so-good way of doing it
age=0

def setAge(a):
global age

setAge(100)
print age

# Prints "100"


了解对象(随后谈到)后,你会发现更好的解决这个问题的办法是使用一个有age属
性和setAge方法的对象。在数据结构那段,你也将会发现一些函数改变它的环境的更好的
例子。
好了--那么真正的函数是什么样?什么是函数呢,事实上?数学函数象一种“机
器”,获得输入然后计算结果。它会每次返回同样的结果,如果每次提供它同样的输入。
例如:

def square(x):
return x*x


这和数学上的函数f(x)=x*x 一样。它的行为象一个精确的函数,仅仅依赖于它的输
入,在任何情况下都不改变它的环境。

所以--我这里描绘了两种构造函数的方法:一种类型更象是过程,不返回任何结
果;另一种更象是数学上的函数,(几乎)什么也不做就是为了返回一个结果。当然,在
这两种极端事物之间做某些事情是可能的,尽管当函数改变事物的时候,它应该清楚它改
变了。你可以通过标记它们的名字区分它们,例如为“纯粹”的函数使用象square这样的
名词而对类似过程那样的函数使用象setAge这样命令式的名字。

更多类型-数据结构
9. 更多类型-数据结构

现在--你已经知道了不少:怎样输入输出,怎样设计复杂的运算法则(程序)来执
行数学运算,但是好戏还在后头呢。

截止目前我们都在程序中使用了哪些成份呢?数字和字符串,对不对?没意思的种
类……现在让我们引入两三个其它的成份来让事情变得更有意思些。

数据结构是种组织数据的成份。(惊奇,吃惊……)单个的数据没有什么真正的数据
结构,是不是?但是假设我们需要很多数放在一起做为一个成份--那就需要某种结构。
例如,我们可能想要一个数据列表。那很容易:

[3, 6, 78, 93]

在循环那段我提到了列表,但没真正描述它。好--这里说的就是你如何创建它。只
需要列出元素,用逗号分开,再加上方括号就行了。


来看一个计算素数(只能被1和它本身整除的数)的例子:

# Calculate all the primes below 1000
# (Not the best way to do it, but...)

result = [1]
candidates = range(3, 1000)
base = 2
product = base

while candidates:
while product < 1000:
if product in candidates:
candidates.remove(product)
product = product+base
result.append(base)
base = candidates[0]
product = base
del candidates[0]
result.append(base)
print result


这个例子中的新东西……

内建函数range事实上返回一个列表,可以象所有其它列表那样使用。(它包括第
一个数,但是不包括最后一个数。)

列表可以当作逻辑变量使用。如果它非空,则为true,否则为false。因此,while
candidates意思是“while名称为candidates的列表非空时”或者简单的说“while存
在candidates时”。

你可以用if someElement in somelist来检查一个元素是否在列表中。

你可以用someList.remove(someElement)来删除someList中的someElement。

你可以用someList.append(something)为一个列表添加元素。事实上,你也可以使
用“+”(象someList = someList+[something])。但是效率不是太高。

你可以通过在列表名之后加上用括号括起来的表示某元素位置的数字(很奇怪,列
表的第1个元素,位置是0)来获得列表的某个元素。因此someList[3]是someList
列表的第四个元素(依次类推)。

你可以使用关键字del删除变量。它也可以用来删除列表中的元素(就象这里)。
因此del someList[0]删除someList 列表中的第一个元素。如果删除前列表是[1, 2,
3],删除后就变成了[2, 3]。

在继续叙述索引列表中的元素之前,我简单解释一下上面的例子。

这是古老算术的一个版本,称为“The Sieve of Erastothenes”(类似这样)。它考量一
系列给定数字(在本例中是一个列表),然后有组织的删除已知不是素数的数字。如何知
道?只要看看它们是不是可以被分解为其它两个数就可以了。

我们从一个包含数字[2...999]的候选列表开始--我们知道1是素数(事实上,它可能
是也可能不是,看你问谁了),我们想得到小于1000的所有素数。(事实上,我们的候
选列表是[3...999],但是2也是候选数字,因为它是我们的第一个base)。我们还有个叫result的列表,它任何时间都包含着最新的结果。最初的时候,它只包含1。我们还有个叫base的变量。每次循环,我们删除是它的倍数的数字(它总是候选列表中最小的数)。每次循环之后,我们知道剩下的最小的数是素数(因为所有可以分解的数我们都删除了)。

因此,我们把它加入result,并把它设为新的base,然后从列表里移除它(

这样就不会对
它重复计算了)。当候选列表为空时,result列表将包含所有的素数。精巧吧,哈!
思考一下:第一次循环有什么特别吗?那时base 是2,但它一样经过了筛选。为什
么?为什么这不发生在其它的base值身上?我们打算移除product时能否确定它在候选列
表中呢?为什么?

接下来是什么呢?哦,是的……索引。还有切片。它们是从python列表中获得单个
元素的方法。你已经见到了普通的索引行为。它相当简单。事实上,我已经告诉了你所有
你需要知道的关于它的东西,除了一件事:负数索引从列表的末尾向前计算。所以,
someList[-1]是someList的最后一个元素,someList[-2]是它之前的一个元素,依次类
推。

切片,仍然,对你来说是陌生的。它和索引相似,除了切片可以获得列表中的所有的
元素,而不仅仅是单个的元素。这如何做呢?象这样:

food = [“spam”, “spam”, “eggs”, “sausages”, “spam”]
print food[2:4]

# Prints “['eggs', 'sausages']”


继续抽象-对象和面向对象编程
10. 继续抽象-对象和面向对象编程

现在有个比较热门的词叫做“面向对象编程”。

就象本段标题暗示的那样,面向对象编程仅仅是另外一种抽象细节的方式。程序通过
命名将简单的描述抽象为复杂的操作。在面向对象编程时,我们不仅可以这样对待程序,
还可以把它们做为对象。(现在,这肯定会让你吃惊,哈!)例如,如果编写烧火腿程
序,我们不用编写很多过程来处理温度、时间、成份等等,我们可以把它们结合为一个火
腿对象。或者,也许我们可以再有炉子对象和时钟对象……那么,象温度这类事物就变成
了火腿对象的一个属性,而时间可以从时钟对象读取。要使用我们的程序做某些事,我们
可以教给我们的对象某些方法;比如,炉子应当知道如何烹制火腿等。

那么--在python中我们如何做呢?我们不能直接制造一个对象。不能直接制造一个
炉子,而是做一个菜谱来描述炉子应该是什么样。这份菜谱因此就描述了一个被我们称为
炉子的一类对象。一个非常简单的炉子类可能是这样:

class Oven:

def insertSpam(self, spam):
self.spam = spam

def getSpam(self):
return self.spam


这看起来很难理解,还是怎样呢?

这个例子中的新东西……

对象的类用关键字class定义。

类的名称通常以大写字母开始,而函数和变量(还有属性和方法)的名称以小写字
母开始。

方法(也就是让对象知道如何去做的函数和操作)的定义没有特别,但是要在类的
定义里面。

所有对象的方法应当有的第一

个参数叫做self(或者类似的……)原因很快就清楚
了。

对象的属性和方法可以这样来访问:mySpam.temperature = 2 或者dilbert.be_nice
()。

我能猜到上面例子中的某些东西你仍然不清楚。例如,什么是self?还有,现在我们
有了对象菜谱(也就是类),我们怎样事实上构造一个对象呢?

我们先颠倒一下顺序。对象通过象引用函数那样引用类名来创建:

myOven = Oven()


myOven包含了一个Oven对象,通常叫做Oven类的一个实例。假设我们也构造好了
一个Spam类,那么我们可象这样做:

mySpam = Spam()
myOven.insertSpam(mySpam)


myOven.spam现在将包含mySpam。怎么回事?因为,我们调用一个对象的某个方法
时,第一个参数,通常称为self,总是包含对象本身。(巧妙,哈!)这样,self.spam =spam这一行设置当前Oven对象的spam属性的值为参数spam。注意它们是两个不同的事物,尽管在这个例子中它们都被称为spam。

练习3答案
11. 练习3答案

这是这个运算法则的一个非常简洁的版本:

def euclid(a, b):
while b:
a, b = b, a%b
return a


-完-


PYTHON教程
第一章介绍
脚本语言是类似DOS批处理、UNIX shell程序的语言。脚本语言不需要每次编译再执行,并且在执行中可以很容易地访问正在运行的程序,甚至可以动态地修改正在运行的程序,适用于快速地开发以及完成一些简单的任务。在使用脚本语言时常常需要增的新的功能,但有时因为脚本语言本来就已经很慢、很大、很复杂了而不能实现;或者,所需的功能涉及只能用C语言提供的系统调用或其他函数——通常所要解决的问题没有重要到必须用C语言重写的程度;或者,解决问题需要诸如可变长度字符串等数据类型(如文件名的有序列表),这样的数据类型在脚本语言中十分容易而C语言则需要很多工作才能实现;或者,编程者不熟悉C语言:这些情况下还是可以使用脚本语言的。 在这样的情况下,Python可能正好适合你的需要。Python使用简单,但它是一个真正的程序语言,而且比shell提供了更多结构和对大型程序的支持。另一方面,它比C提供更多的错误检查,它是一个非常高级的语言,内置了各种高级数据结构,如灵活的数组和字典,这些数据结构要用C高效实现的话可能要花费你几天的时间。由于Python具有更一般的数据结构,它比Awk甚至Perl适用的范围都广,而许多东西在Python内至少和在这些语言内一样容易。 Python允许你把程序分解为模块,模块可以在其他Python程序中重用。它带有一大批标准模块可以作为你自己的程序的基础——或作为学习Python编程的例子。系统还提供了关于文件

输入输出、系统调用、插座(sockets)的东西,甚至提供了窗口系统(STDWIN)的通用接口。 Python是一个解释性语言,因为不需要编译和连接所以能节省大量的程序开发时间。解释程序可以交互使用,这样可以可以很容易地试验语言的各种特色,写只用一次的程序,或在从底向上程序开发中测试函数。它也是一个方便的计算器。 Python允许你写出非常严谨而且可读的程序。用Python写的程序通常都比相应的C程序要短,因为如下几个理由: 高级的数据结构允许你用一个语句表达复杂的操作; 复合语句是靠缩进而不是用表示开始和结束的括号; 不需要变量声明或参量声明。 Python是可扩充的:如果你会用C语言编程就很容易为解释程序增加新的内置函数或模块,这样可以以最快速度执行关键操作,或把Python程序和只能以二进制码提供的库(如不同厂商提供的图形库)连接起来。当你变得确实很在行时你可以把Python解释器与用C写的应用相连接,把它作为该应用的扩展或命令语言。 Python的命名是由BBC的“Monty Python's Flying Circus”节目而得,与蟒蛇没有什么关系。
第二章解释程序的使用 在命令行键入 python 或在Windows环境下双击相应的图标可以进入Python的解释程序。如果要运行储存在文件中的Python程序,可以用 python 文件名 的形式。 进入解释程序的环境后,解释程序称为处于交互状态。在这种状态下系统用主提示提示输入下一个命令,这一般是三个大于号(>>>),如果需要续行系统用次提示提示输入,缺省为三个小数点(...)。在主提示下键入文件尾符号(在UNIX中为Control-D,在DOS或Windows中为Control-Z)可以正常退出解释程序。 Python解释程序的有些版本支持命令行编辑和命令历史,使用用Emacs或vi的键组合。 第三章基本使用 下面我们用例子来介绍Python的基本用法。在例子中,用户输入和系统输出靠有没有提示(>>>和...)来分别。如果要试这些例子的话,需要键入提示后的所有命令,例子中没有提示的行是系统的输出。注意只有次提示的行意味着需要键入一个空行,这用于结束多行命令。 3.1 用Python作计算器使用 启动解释程序,等待主提示>>>出现。解释程序可以作为计算器使用。键入一个表达式,解释程序就可以输出结果。表达式的写法很直观:+,-,*,/, %, **等算符的作用和其它大多数语言(如Pascal或C)没什么差别,括号可以用来组合。例如: >>>2+2 4 >>># 这是一个注释... 2+24>>>2+2 # 和代码在同一行的注释4>>>(50-5*6)/45>>># 整数除法得下面的整数... 7/32>>>7/-3-3>>> 和C中一样,等于号用来给变量赋值,赋值的结果不显示:

>>>width = 20>>>height = 5*9>>>width * height900>>> 可以同时给几个变量赋同一个值: >>>x = y = z = 0 # 把 x, y 和 z赋零 >>>x0>>>y0>>>z0>>> Python完全支持浮点数,混合类型的运算会把整数先转换成浮点数: >>>4 * 2.5 / 3.33.0303030303>>>7.0 / 23.5>>> Python也提供了复数,方法是用j和J作为虚数单位,如1+1j,3.14e-10j,等等。 3.2. 字符串 Python除处理数字外还可以处理字符串,字符串用单撇号或双撇号包裹: >>>'spam eggs''spam eggs'>>>'doesn\'t'"doesn't">>>"doesn't""doesn't">>>'"Yes,"he said.''"Yes,"he said.'>>>"\"Yes,\"he said."'"Yes,"he said.'>>>'"Isn\'t,"she said.''"Isn\'t,"she said.'>>> 字符串输出格式与输入的样子相同,都是用撇号包裹,撇号和其它特殊字符用用反斜杠转义。如果字符串中有单撇号而没有双撇号则用双撇号包裹,否则应该用单撇号包裹。后面要介绍的print语句可以不带撇号或转义输出字符串。 字符串可以用+号连接起来,用*号重复: >>>word = 'Help' + 'A'>>>word'HelpA'>>>'<' + word*5 + '>'''>>> 字符串可以象在C中那样用下标索引,字符串的第一个字符下标为0。 Python没有单独的字符数据类型,一个字符就是长度为一的字符串。象在Icon语言中那样,可以用片段(slice)记号来指定子串,片段即用冒号隔开的两个下标。 >>>word[4]'A'>>>word[0:2]'He'>>>word[2:4]'lp'>>> 片段有很好的缺省值:第一下标省略时缺省为零,第二下标省略时缺省为字符串的长度。 >>>word[:2] # 前两个字符'He'>>>word[2:] # 除前两个字符串外的部分'lpA'>>> 注意s[:i] + s[i:] 等于 s 是片段运算的一个有用的恒等式。 >>>word[:2] + word[2:]'HelpA'>>>word[:3] + word[3:] 'HelpA'>>> 不合理的片段下标可以很好地得到解释:过大的下标被换成字符串长度,上界小于下界时返回空串。 >>>word[1:100]'elpA'>>>word[10:]''>>>word[2:1]''>>> 下标允许为负数,这时从右向左数。例如: >>>word[-1] # 最后一个字符'A'>>>word[-2] # 倒数第二个字符'p'>>>word[-2:] # 最后两个字符'pA'>>>word[:-2] # 除最后两个字符外的部分'Hel'>>> 但要注意的是 -0 实际还是 0,所以它不会从右向左数! >>>word[-0] # (因为 -0 等于 0)'H'>>> 超出范围的片段下标被截断,但在非片段的情况下不要这样: >>>word[-100:]'HelpA'>>>word[-10] # 错误Traceback (innermost last):File"", line 1IndexError: string index out of range >>> 记住片段意义的最好方法是把下标看成是字符之间的点,第一个字符的左边界号码为0。有n个字符的字符串的最后一个字符的右边界下标为n,例如: +---+---+---+---+---+| H | e | l | p | A |+---+---+---+---+---+0 1 2 3 4 5-5 -4 -3 -2 -1 第一行数字给出字符串中下标0到5的位置,第二行给出相应的负下标。从i到j的片段

由在边界i和j之间的字符组成。 对于非负下标,如果下标都在界内,则片段的长度为下标的差。例如,word[1:3] 的长度为 2。 内置函数len()返回字符串的长度: >>>s = 'supercalifragilisticexpialidocious'>>>len(s)34>>> 多行的长字符串也可以用行尾反斜杠续行,续行的行首空白不被忽略,如 hello ="This is a rather long string containing\n\several lines of text just as you would do in C.\n\Note that whitespace at the beginning of the line is\significant.\n"print hello 结果为 This is a rather long string containingseveral lines of text just as you would do in C.Note that whitespace at the beginning of the line is significant. 对于特别长的字符串(比如包含说明的几段文字),如果用上面的方式每行都用\n\结尾是很麻烦的,特别是这样无法用象Emacs这样的功能强大的编辑器重新编排。对这种情况,可以使用三重撇号,例如 hello =""" This string is bounded by triple double quotes (3 times").Unescaped newlines in the string are retained, though \it is still possible\nto use all normal escape sequences. Whitespace at the beginning of a line issignificant. If you need to include three opening quotesyou have to escape at least one of them, e.g. \""". This string ends in a newline.""" 三重撇号字符串也可以用三个单撇号,没有任何语义差别。 多行的字符串常量可以直接连接起来,字符串常量之间用空格分隔则在编译时可以自动连接起来,这样可以把一个长字符串连接起来而不需要牺牲缩进对齐或性能,不象用加号连接需要运算,也不象字符串串内的换行其行首空格需要保持。 3.3 列表 Python中有几种复合数据类型,用来把其它值组合到一起。其中最灵活的是列表,可以写成在方括号之间用逗号隔开的若干值(项)。列表的项不必取同一类型。 >>>a = ['spam', 'eggs', 100, 1234]>>>a['spam', 'eggs', 100, 1234]>>> 象字符串下标那样,列表下标从0开始,列表可以取片段,可以连接,等等: >>>a[0]'spam'>>>a[3]1234>>>a[-2]100>>>a[1:-1]['eggs', 100]>>>a[:2] + ['bacon', 2*2]['spam', 'eggs', 'bacon', 4]>>>3*a[:3] + ['Boe!']['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boe!']>>> 与字符串不同的是列表是可变的,可以修改列表的每个元素: >>>a['spam', 'eggs', 100, 1234]>>>a[2] = a[2] + 23>>>a['spam', 'eggs', 123, 1234]>>> 也可以给一个片段重新赋值,这甚至可以改变表的大小: >>># 替换若干项:... a[0:2] = [1, 12]>>>a[1, 12, 123, 1234]>>># 去掉若干项:... a[0:2] = []>>>a[123, 1234]>>># 插入若干项:... a[1:1] = ['bletch', 'xyzzy']>>>a[123, 'bletch', 'xyzzy', 1234]>>>a[:0] = a # 在开头插入自身>>>a[123, 'bletch', 'xyzzy', 1234, 123,'bletch', 'xyzzy', 1234]>>> 内置函数也使用于列表: >>>len(a)8>>> 可以建立嵌套列表(表的元

素也是列表),如: >>>q = [2, 3]>>>p = [1, q, 4]>>>len(p)3>>>p[1][2, 3]>>>p[1][0]2>>>p[1].append('xtra') # 列表方法>>>p[1, [2, 3, 'xtra'], 4]>>>q[2, 3, 'xtra']>>> 注意这个例子中p[1]和q实际是同一个对象!也就是说它们只不过是同一个东西的两个名字(引用)而已。 3.4 编程初步 Python当然不是只能用来把两个数加到一起,它可以完成很复杂的工作。例如,我们可以写出Fibonacci序列的开始几个: >>># Fibonacci 序列:... # 两个元素的和定义下一个... a, b = 0, 1>>>while b<10:... print b... a, b = b, a+b...112358>>> 这个例子介绍了几个新特色。 第一行包含一个多重赋值:变量a和b同时得到新值0和1。在最后一行又用了多重赋值,我们可以看出赋值时先把右边都算出后再进行赋值。 while循环当循环条件(这里即: b<10)成立时不断执行。在Python中和C中一样,非零整数值为真值,零为假值。条件也可以是字符串或列表或任何序列,长度为非零的为真,空序列为假。例子中所用的是一个简单比较。标准的比较算符和C一样: <,>, ==,<=,>= 和 !=。 循环体是缩进的:缩进是Python用来组合语句的方式。Python目前还不能提供智能自动缩进,所以你需要自己为每个缩进行键入制表符或空格。实际使用中你可以用文本编辑程序为Python 准备复杂的输入,多数文本编辑程序都有自动缩进的功能。在交互输入复合语句时必修附加一个空行以指示复合语句的完成(因为解释程序无法猜到哪是语句的最后一行)。print语句显示后面的表达式值。这和直接写出表达式不同,它可以显示多个表达式和字符串,而且可以用于程序文件中。显示时字符串没有撇号,各项目之间插入一个空格,所以你可以以精美的格式显示,如: >>>i = 256*256>>>print 'The value of i is', iThe value of i is 65536>>> 在尾部写一个逗号可以避免最后换行: >>>a, b = 0, 1>>>while b<1000:... print b,... a, b = b, a+b...1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987>>> 注意如果前一行没有结束的话系统在显示提示之前先换行。 Python还提供了和C语言一样的printf格式的输出方式,这是用%实现的,左边是格式,如: >>>print 'The value of 1/7 is approximately %5.3f.' % 0.142857The value of 1/7 is approximately 0.143.>>> 如果有多个需要输出的项百分号右边的项可以是一个序组,如 >>>print"Name: %-10s Age: %3d"% ("White", 31)Name: White Age: 31 第四章流程控制 前面我们已经见到了如何由用while结构控制流程运行。这一章我们介绍更多的控制结构。Python具有和其它语言类似的控制结构但略有差别。 4.1 If 语句 If 语句可能是最基本的程序分支语句了。例如: >>>if x<0:... x = 0... print 'Negative changed to zero'... elif x == 0:... print 'Zero'... elif

x == 1:... print 'Single'... else:... print 'More'... 可以有零到多个elif部分,else部分可选。关键字elif是else if的缩写,这样可以缩短语句行长度。其它语言中switch 或 case 语句可以用if...elif...elif...语句组来实现。 4.2 for 语句 Python中的for语句与你可能熟悉的C或者Pascal中的相应语句略有不同。不象Pascal 那样总是对数字序列进行循环,也不是象C中那样完全由程序员自由地控制循环条件和循环体,Python的for循环是对任意种类的序列(如列表或字符串)按出现次序遍历每一项。例如: >>># 计算字符串长:... a = ['cat', 'window', 'defenestrate']>>>for x in a:... print x, len(x)...cat 3window 6defenestrate 12>>> 尽量不要在循环体内修改用来控制循环的序列(当然,只有可变的序列类型如列表才有可能被修改),这样程序可能会出问题。如果需要这样,比如说要复制某些项,可以用序列的副本来控制循环。片段记号让你很容易生成副本: >>>for x in a[:]: # 生成整个列表的片段副本... if len(x)>6: a.insert(0, x)...>>>a['defenestrate', 'cat', 'window', 'defenestrate']>>> 结果是把列表中长度超过6个字符的字符串插入到列表开头。 4.3 range() 函数 如果确实需要对一列数字进行循环的话,可以使用内置函数range()。它生成包含数字序列的列表,如: >>>range(10)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> 注意给出的终点永远不出现在生成的列表中,range(10)生成一个十个数的列表,恰好是长度为10的序列的合法下标的各个值。也可以指定不同的起始点,或者指定不同的间隔(甚至负数): >>>range(5, 10)[5, 6, 7, 8, 9]>>>range(0, 10, 3)[0, 3, 6, 9]>>>range(-10, -100, -30)[-10, -40, -70]>>> 为了对序列的下标进行循环,如下联合使用range() 和 len(): >>>a = ['Mary', 'had', 'a', 'little', 'lamb']>>>for i in range(len(a)):... print i, a[i]...0 Mary1 had2 a3 little4 lamb>>> 4.4 break语句,continue语句和循环中的else子句 如同C语言一样,break语句跳出其所处的最内层的for 或 while循环,continue语句继续下一循环步。 循环语句还可以带一个 else 子句,当循环正常结束时执行其内容,但如果循环是用break 语句跳出的则不执行其内容。下例说明了这种用法,此例求素数: >>>for n in range(2, 10):... for x in range(2, n):... if n % x == 0:... print n, 'equals', x, '*', n/x... break... else:... print n, 'is a prime number'...2 is a prime number3 is a prime number4 equals 2 * 25 is a prime number6 equals 2 * 37 is a prime number8 equals 2 * 49 equals 3 * 3>>> 4.5 pass 语句 pass语句不执行任何操作,当语法要求一个语句而程序不需要执行操作时就用此语句。例如: >>>while 1:... pass # 等待键盘中断... 4.6 函数定义 我们可以定义一个函数用来计算某一界限以下的所有Fibon

acci序列值: >>>def fib(n): # 写出 n 以下的所有Fibonacci序列值... a, b = 0, 1... while b>># 调用刚刚定义的函数:... fib(2000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597>>> 其中关键字 def 开始一个函数定义,其后应该是函数名,括号内的形参表,以冒号结束。构成函数体的各语句从下一行开始,用一个制表符缩进。函数的第一个语句可以是一个字符串,如果是的话,这个字符串就是函数的文档字符串,简称为docstring。有一些工具可以利用文档字符串自动生成可打印的文档,或者让用户交互地浏览代码,所以在自己编程时加入文档字符串是一个好习惯,应该养成这样的习惯。 函数在执行时对局部变量引入一个新的符号表。函数中的变量赋值都存入局部符号表;引用变量时变量名先从局部符号表中查找,然后在全局符号表中查找,最后从内置的名字中查找。因此,在函数中不能直接对全局变量赋值(除非用了global语句来说明),但可以引用全局变量的值。 函数调用的实参被引入函数的局部符号表,即函数的参数是按值调用的。函数再调用其它函数时为该函数生成一个新的符号表。但是严格地说,函数的调用是按引用调用的,因为如果参数是一个可变类型如列表的话在函数中改变形参的内容将导致实参的内容被改变(不改变的是实参名字的绑定关系)。 函数定义把函数名放入当前符号表。函数名的值类型为用户自定义函数,这个值可以赋给另一个名字,从而这个名字也代表相同的函数。这可以作为一般的改名方法: >>>fib>>>f = fib>>>f(100)1 1 2 3 5 8 13 21 34 55 89>>> 你可能会说 fib 不是函数而是过程。Python和C一样,过程只是不返回值的函数。实际上,严格地说,过程也返回一个值,只不过是一个很没意思的值。这个值叫做 None(这是一个内置的名字)。解释程序交互运行时如果只需要显示这个值的话就会忽略不显示。如果希望显示的话可以用 print 语句: >>>print fib(0)None>>> 也可以写一个函数返回Fibonacci 序列的数值列表而不是显示这些值: >>>def fib2(n): # 返回直到n的Fibonacci 序列值... result = []... a, b = 0, 1... while b>>f100 = fib2(100) # 调用>>>f100 # 输出结果[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] >>> 这个例子也演示了新的Python特色:return语句从函数中退出并返回一个值。不带返回值的return可以从过程中间退出,运行到过程的末尾也可以退出,这两种情况下返回None。 语句result.append(b)调用列表对象result的一个方法。方法是“属于”一个对象的函数,引用格式

为obj.methodname,其中obj是某个对象(也允许是一个表达式), methodname 是由该对象的类型定义的一个方法的名字。不同的不同的方法。不同类型的方法可以使用相同的名字而不致引起误解。(可以定义自己的对象类型和方法,使用类,本文后面会讨论这个话题)。例子中的append()方法时列表对象的方法,它在列表末尾增加一个新元素。在本例中这等价于“result = result + [b]”,只是更有效。 4.7 函数参数 可以定义使用可变个数参数的函数。这样的定义方法有三种,可以联合使用。 4.7.1 参数缺省值 可以为一个参数或几个参数指定缺省值。这样定义的函数在调用时实参个数可以比定义时少。例如: def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):while 1:ok = raw_input(prompt)if ok in ('y', 'ye', 'yes'): return 1if ok in ('n', 'no', 'nop', 'nope'): return 0retries = retries - 1if retries<0: raise IOError, 'refusenik user'print complaint 这个函数在调用时既可以这样调用:ask_ok('Do you really want to quit?'),或者可以这样调用:ask_ok('OK to overwrite the file?', 2)。缺省值是在函数定义时的定义作用域中计算的,所以例如: i = 5def f(arg = i): print argi = 6f() 将显示5。 注意:缺省值只计算一次。当缺省值是可变对象如列表或字典时这一点是要注意的。例如,以下函数会在以后的调用中累加它的值: def f(a, l = []):l.append(a)return lprint f(1)print f(2)print f(3)This will print [1][1, 2][1, 2, 3] 如果你不希望缺省值在连续的调用中被保留,可以象下面这样改写函数: def f(a, l = None):if l is None:l = []l.append(a)return l 4.7.2 关键字参数 函数调用时也可以象“关键字 = 值”这样指定实参,其中关键字是定义时使用的形参的名字。例如: def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):print"-- This parrot wouldn't", action,print"if you put", voltage,"Volts through it."print"-- Lovely plumage, the", typeprint"-- It's", state,"!" 可以用如下几种方式调用: parrot(1000) # 缺省值parrot(action = 'VOOOOOM', voltage = 1000000) # 关键字,缺省值,次序可变parrot('a thousand', state = 'pushing up the daisies') # 位置参数,缺省值,关键字parrot('a million', 'bereft of life', 'jump') # 位置参数,缺省值 但以下几种调用方式是错误的: parrot() # 非缺省的参数没有提供parrot(voltage=5.0, 'dead') # 关键字参数后面又出现了非关键字参数parrot(110, voltage=220) # 参数值重复提供parrot(actor='John Cleese') # 未知关键字 一般说来,实参表中位置参数在前,关键字参数在后,关键字名字必须是形参名字。形参有没有缺省值都可以用关键字参数的形式调用。每一形参至多只能对应一个实参,因此,已经由位置参数传入值

的形参就不能在同一调用中再作为关键字参数。 如果形参表中有一个形为**name的形参,在调用时这个形参可以接收一个字典,字典中包含所有不与任何形参匹配的关键字参数。形参表中还可以使用一个特殊的如*name的形参,它将接受所有不能匹配的位置参数组成的一个序表。*name只能在**name之前出现。例如,如果定义了下面的函数: def cheeseshop(kind, *arguments, **keywords):print"-- Do you have any", kind, '?'print"-- I'm sorry, we're all out of", kindfor arg in arguments: print argprint '-'*40for kw in keywords.keys(): print kw, ':', keywords[kw] 就可以象下面这样调用: cheeseshop('Limburger',"It's very runny, sir.","It's really very, VERY runny, sir.",client='John Cleese',shopkeeper='Michael Palin',sketch='Cheese Shop Sketch') 结果显示: -- Do you have any Limburger ?-- I'm sorry, we're all out of LimburgerIt's very runny, sir.It's really very, VERY runny, sir.----------------------------------------client : John Cleeseshopkeeper : Michael Palinsketch : Cheese Shop Sketch 4.7.3 任意个数参数 在所有有名的形参的后面可以有两个特殊的形参,一个以*args的形式命名,一个以**kw 的形式命名。有了*args形式的形参后函数在调用时就可以在正常的能匹配的实参表后面输入任意个数的参数,这些参数组成一个序表赋给args形参,不能匹配的关键字参数组成一个字典赋给kw形参。在任意个数形参之前可以有0到多个正常的参数。例如: def fprintf(file, format, *args):file.write(format % args) 4.7.4 Lambda形式 因为许多人的要求,Python中加入了一些在函数编程语言和Lisp中常见的功能。可以用lambda 关键字来定义小的无名函数。这是一个返回其两个参数的和的函数:“lambda a, b: a+b”。Lambda形式可以用于任何需要函数对象的地方。从句法上讲lambda形式局限于一个表达式。从语义上讲,这只是正常的函数定义的句法甜食。像嵌套函数定义一样,lambda形式不能访问包含其定义的作用域中的变量,但审慎地使用缺省参数之可以绕过这个限制。例如: def make_incrementor(n):return lambda x, incr=n: x+incr 4.7.5 文档字符串 关于文档字符串的内容与格式正在形成一些惯例。第一行应该为简短的对象目的概括说明。为了简明起见,这一行不应该提及对象的名字或类型,因为这些可以通过其他途径得知(当然如果对象名字就是一个描述函数操作的动词则当然可以提及其名字)。着以行应该用大些字母开始,以句点结尾。如果文档字符串中有多行,第二行应该是空行,把概括说明与其它说明分开。以下的行可以是一段或几段,描述对象的调用方法,它的副作用,等等。 Python的扫描程序不会从多行字符串中去掉缩进空白,所以处理文档

的工具需要自己处理缩进。只要遵循如下的惯例就可以有利于缩进空白的处理。在第一行之后的第一个非空白的行决定整个文档字符串的缩进数量(我们不用第一行,因为它经常是直接跟在表示字符串开始的引号后面)。文档字符串中除第一行以外的各行都要删除等价于此行的缩进量的空白。对制表符将扩展为空格后再删除。 第五章 Python数据结构 本章更详细地讨论一些已经讲过的数据类型的使用,并引入一些新的类型。 5.1 列表 列表数据类型还有其它一些方法。下面是列表对象的所有方法: insert(i, x) ---- 在指定位置插入一项。第一自变量是要在哪一个元素前面插入,用下标表示。例如,a.insert(0, x)在列表前面插入,a.insert(len(a), x)等价于a.append(x) 。 append(x) ---- 等价于a.insert(len(a), x) index(x) ---- 在列表中查找值x然后返回第一个值为x的元素的下标。没有找到时出错。 remove(x) ---- 从列表中删去第一个值为x的元素,找不到时出错。 sort() ---- 对列表元素在原位排序。注意这个方法改变列表,而不是返回排序后的列表。 reverse() ---- 把列表元素反序。改变列表。 count(x) ---- 返回x在列表中出现的次数。 下例使用了所有的列表方法: >>>a = [66.6, 333, 333, 1, 1234.5]>>>print a.count(333), a.count(66.6), a.count('x')2 1 0>>>a.insert(2, -1)>>>a.append(333)>>>a[66.6, 333, -1, 333, 1, 1234.5, 333]>>>a.index(333)1>>>a.remove(333)>>>a[66.6, -1, 333, 1, 1234.5, 333]>>>a.reverse()>>>a[333, 1234.5, 1, 333, -1, 66.6]>>>a.sort()>>>a[-1, 1, 66.6, 333, 333, 1234.5] 5.1.1 函数程序设计工具 Python中有一些函数程序设计风格的东西,例如前面我们看到的lambda形式。关于列表有三个非常有用的内置函数:filter(), map()和reduce()。 “filter(函数, 序列)”返回一个序列(尽可能与原来同类型),序列元素是原序列中由指定的函数筛选出来的那些,筛选规则是“函数(序列元素)=true”。filter()可以用来取出满足条件的子集。例如,为了计算一些素数: >>>def f(x): return x % 2 != 0 and x % 3 != 0...>>>filter(f, range(2, 25))[5, 7, 11, 13, 17, 19, 23] “map(函数,序列)”对指定序列的每一项调用指定的函数,结果为返回值组成的列表。map() 可以对序列进行隐式循环。例如,要计算三次方,可用: >>>def cube(x): return x*x*x...>>>map(cube, range(1, 11))[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000] 可以有多个序列作为自变量,这时指定的函数必须也有相同个数的自变量,函数从每个序列分别取出对应元素作为自变量进行调用(如果某个序列比其它的短则取出的值是None)。如果指定的函数是None,map()把它当成一个返回自己的自变量的恒同函数。在函数用None的情况下指定多个序列可以把多

个序列搭配起来,比如“map(None, list1, list2)”可以把两个列表组合为一个成对值的列表。见下例: >>>seq = range(8)>>>def square(x): return x*x...>>>map(None, seq, map(square, seq))[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49)] “reduce(函数, 序列)”用来进行类似累加这样的操作,这里的函数是一个两个子变量的函数,reduce()先对序列的前两项调用函数得到一个结果,然后对结果和序列下一项调用函数得到一个新结果,如此进行到序列尾部。例如,要计算1到10的和: >>>def add(x,y): return x+y...>>>reduce(add, range(1, 11))55 如果序列中只有一个值则返回这个值,序列为空时会产生例外。可以指定第三个自变量作为初始值。有初始值时对空序列函数将返回初始值,否则函数先对初始值和序列第一项作用,然后对结果和序列下一项作用,如此进行到序列尾。例如: >>>def sum(seq):... def add(x,y): return x+y... return reduce(add, seq, 0)...>>>sum(range(1, 11))55>>>sum([])0 5.2 del语句 上面我们看到,列表的remove()方法可以从列表中删去某个取值的项,我们还可以用del 语句来删除指定下标的项。也可以用del语句从列表中删除一个片断(前面我们是用给片断赋空列表的办法删除片断的)。例如: >>>a[-1, 1, 66.6, 333, 333, 1234.5]>>>del a[0]>>>a[1, 66.6, 333, 333, 1234.5]>>>del a[2:4]>>>a[1, 66.6, 1234.5] del也可以用来删除整个变量,例如: >>>del a 变量删除以后再引用该变量就会出错(除非又给它赋值了)。后面我们还会看到del的其它一些应用。 5.3 序表和序列 我们看到列表和字符串有许多共同点,例如,下标和片断运算。它们都属于序列数据类型。因为Python是一个正在不断发展的语言,以后还可能会加入其它的序列数据类型。现在还有一种标准的序列数据类型,称为序表(tuple)。 序表由一系列值用逗号分隔而成,例如: >>>t = 12345, 54321, 'hello!'>>>t[0]12345>>>t(12345, 54321, 'hello!')>>># 序表允许嵌套:... u = t, (1, 2, 3, 4, 5)>>>u((12345, 54321, 'hello!'), (1, 2, 3, 4, 5)) 输出的序表总是用括号包围,这样可以保证嵌套序表得以正确解释。输入时可以有括号也可以没有括号,当经常是必须有括号(如果序表是一个大表达式的一部分)。 序表有许多用处,例如,(x,y)坐标对,数据库中的职工纪录,等等。序表与字符串一样是不可变的:不允许对序表的某一项赋值。 生成序表时对0项或1项的序表有特殊的规定:空序表用一对空括号表示;只有一项的序表用一个之后面跟一个抖好表示(指把这个值放在括号内是不够的)。这样写不够美观,但很有效。例如: >>>empty = ()>>>singleton = 'hello', #<-- note trailing comma>>>len(empty)0>>>len(singleton)1>>>sin

相关文档
最新文档