12. 简明 Python 教程
第1章 介绍
上一页 程序员的话 下一页
程序员的话
读一下像ESR这样的超级电脑高手谈Python的话,你会感到十分有意思:
● Eric S. Raymond是《The Cathedral and the Bazaar》的作者、“开放源码”一词的提出人。
他说Python已经成为了他最喜爱的编程语言。这篇文章也是促使我第一次接触Python的
真正原动力。
● Bruce Eckel著名的《Thinking in Java》和《Thinking in C++》的作者。他说没有一种语言
比得上Python使他的工作效率如此之高。同时他说Python可能是唯一一种旨在帮助程序
员把事情弄得更加简单的语言。请阅读完整的采访以获得更详细的内容。
● Peter Norvig是著名的Lisp语言书籍的作者和Google公司的搜索质量主任(感谢Guido van
Rossum告诉我这一点)。他说Python始终是Google的主要部分。事实上你看一下Google
招聘的网页就可以验证这一点。在那个网页上,Python知识是对软件工程师的一个必需
要求。
● Bruce Perens是OpenSource.org和UserLinux项目的一位共同创始人。UserLinux旨在创造一
个可以被多家发行商支持标准的Linux发行版。Python击败了其它竞争对手如Perl和Ruby
成为UserLinux支持的主要编程语言。
上一页 上一级 下一页
为什么不使用
首页 第2章 安装Python
Perl?
25. 简明 Python 教程
第4章 基本概念
上一页 字符串 下一页
字符串
字符串是 字符的序列 。字符串基本上就是一组单词。
我几乎可以保证你在每个Python程序中都要用到字符串,所以请特别留心下面这部分的内容。
下面告诉你如何在Python中使用字符串。
● 使用单引号(')
你可以用单引号指示字符串,就如同'Quote me on this'这样。所有的空白,即空格和制
表符都照原样保留。
● 使用双引号(")
在双引号中的字符串与单引号中的字符串的使用完全相同,例如"What's your name?"。
● 使用三引号('''或""")
利用三引号,你可以指示一个多行的字符串。你可以在三引号中自由的使用单引号和双
引号。例如:
'''This is a multi-line string. This is the first line.
This is the second line.
"What's your name?," I asked.
He said "Bond, James Bond."
'''
● 转义符
假设你想要在一个字符串中包含一个单引号('),那么你该怎么指示这个字符串?例
如,这个字符串是What's your name?。你肯定不会用'What's your name?'来指示它,因为
Python会弄不明白这个字符串从何处开始,何处结束。所以,你需要指明单引号而不是
字符串的结尾。可以通过 转义符 来完成这个任务。你用'来指示单引号——注意这个反
斜杠。现在你可以把字符串表示为'What's your name?'。
另一个表示这个特别的字符串的方法是"What's your name?",即用双引号。类似地,要在
双引号字符串中使用双引号本身的时候,也可以借助于转义符。另外,你可以用转义符
来指示反斜杠本身。
值得注意的一件事是,在一个字符串中,行末的单独一个反斜杠表示字符串在下一行继
续,而不是开始一个新的行。例如:
"This is the first sentence.
This is the second sentence."
等价于"This is the first sentence. This is the second sentence."
● 自然字符串
如果你想要指示某些不需要如转义符那样的特别处理的字符串,那么你需要指定一个自
然字符串。自然字符串通过给字符串加上前缀r或R来指定。例如r"Newlines are indicated
by n"。
● Unicode字符串
Unicode是书写国际文本的标准方法。如果你想要用你的母语如北印度语或阿拉伯语写
文本,那么你需要有一个支持Unicode的编辑器。类似地,Python允许你处理Unicode文
本——你只需要在字符串前加上前缀u或U。例如,u"This is a Unicode string."。
记住,在你处理文本文件的时候使用Unicode字符串,特别是当你知道这个文件含有用
非英语的语言写的文本。
● 字符串是不可变的
这意味着一旦你创造了一个字符串,你就不能再改变它了。虽然这看起来像是一件坏
事,但实际上它不是。我们将会在后面的程序中看到为什么我们说它不是一个缺点。
● 按字面意义级连字符串
如果你把两个字符串按字面意义相邻放着,他们会被Python自动级连。例如,'What's'
'your name?'会被自动转为"What's your name?"。
给C/C++程序员的注释
在Python中没有专门的char数据类型。确实没有需要有这个类型,我相信你不会为此而烦恼。
给Perl/PHP程序员的注释
记住,单引号和双引号字符串是完全相同的——它们没有在任何方面有不同。
给正则表达式用户的注释
一定要用自然字符串处理正则表达式。否则会需要使用很多的反斜杠。例如,后向引用符可以
写成'1'或r'1'。
上一页 上一级 下一页
数 首页 变量
29. 简明 Python 教程
第4章 基本概念
上一页 对象 下一页
对象
记住,Python把在程序中用到的任何东西都称为 对象 。这是从广义上说的。因此我们不会
说“某某 东西 ”,我们说“某个 对象 ”。
给面向对象编程用户的注释
就每一个东西包括数、字符串甚至函数都是对象这一点来说,Python是极其完全地面向对象
的。
我们将看一下如何使用变量和字面意义上的常量。保存下面这个例子,然后运行程序。
如何编写Python程序
下面是保存和运行Python程序的标准流程。
1. 打开你最喜欢的编辑器。
2. 输入例子中的程序代码。
3. 用注释中给出的文件名把它保存为一个文件。我按照惯例把所有的Python程序都以扩展名.
py保存。
4. 运行解释器命令python program.py或者使用IDLE运行程序。你也可以使用先前介绍的可执
行的方法。
例4.1 使用变量和字面意义上的常量
# Filename : var.py
i=5
print i
i=i+1
print i
s = '''This is a multi-line string.
This is the second line.'''
print s
(源文件:code/var.py)
输出
$ python var.py
5
6
This is a multi-line string.
This is the second line.
它如何工作
下面来说明一下这个程序如何工作。首先我们使用赋值运算符(=)把一个字面意义上的常数5
赋给变量i。这一行称为一个语句。语句声明需要做某件事情,在这个地方我们把变量名i与值5
连接在一起。接下来,我们用print语句打印i的值,就是把变量的值打印在屏幕上。
然后我们对i中存储的值加1,再把它存回i。我们打印它时,得到期望的值6。
类似地,我们把一个字面意义上的字符串赋给变量s然后打印它。
给C/C++程序员的注释
使用变量时只需要给它们赋一个值。不需要声明或定义数据类型。
上一页 上一级 下一页
数据类型 首页 逻辑行与物理行
30. 简明 Python 教程
第4章 基本概念
上一页 逻辑行与物理行 下一页
逻辑行与物理行
物理行是你在编写程序时所 看见 的。逻辑行是Python 看见 的单个语句。Python假定每个 物理
行 对应一个 逻辑行 。
逻辑行的例子如print 'Hello World'这样的语句——如果它本身就是一行(就像你在编辑器中看
到的那样),那么它也是一个物理行。
默认地,Python希望每行都只使用一个语句,这样使得代码更加易读。
如果你想要在一个物理行中使用多于一个逻辑行,那么你需要使用分号(;)来特别地标明这
种用法。分号表示一个逻辑行/语句的结束。例如:
i=5
print i
与下面这个相同:
i = 5;
print i;
同样也可以写成:
i = 5; print i;
甚至可以写成:
i = 5; print i
然而,我强烈建议你坚持在每个物理行只写一句逻辑行。仅仅当逻辑行太长的时候,在多于一
个物理行写一个逻辑行。这些都是为了尽可能避免使用分号,从而让代码更加易读。事实上,
我 从来没有 在Python程序中使用过或看到过分号。
下面是一个在多个物理行中写一个逻辑行的例子。它被称为明确的行连接。
s = 'This is a string.
This continues the string.'
print s
它的输出:
This is a string. This continues the string.
类似地,
print
i
与如下写法效果相同:
print i
有时候,有一种暗示的假设,可以使你不需要使用反斜杠。这种情况出现在逻辑行中使用了圆
括号、方括号或波形括号的时候。这被称为暗示的行连接。你会在后面介绍如何使用列表的章
节中看到这种用法。
上一页 上一级 下一页
对象 首页 缩进
31. 简明 Python 教程
第4章 基本概念
上一页 缩进 下一页
缩进
空白在Python中是重要的。事实上行首的空白是重要的。它称为缩进。在逻辑行首的空白(空
格和制表符)用来决定逻辑行的缩进层次,从而用来决定语句的分组。
这意味着同一层次的语句必须有相同的缩进。每一组这样的语句称为一个块。我们将在后面的
章节中看到有关块的用处的例子。
你需要记住的一样东西是错误的缩进会引发错误。例如:
i=5
print 'Value is', i # Error! Notice a single space at the start of the line
print 'I repeat, the value is', i
当你运行这个程序的时候,你会得到下面的错误:
File "whitespace.py", line 4
print 'Value is', i # Error! Notice a single space at the start of the line
^
SyntaxError: invalid syntax
注意,在第二行的行首有一个空格。Python指示的这个错误告诉我们程序的语法是无效的,即
程序没有正确地编写。它告诉你, 你不能随意地开始新的语句块 (当然除了你一直在使用的
主块)。何时你能够使用新块,将会在后面的章节,如控制流中详细介绍。
如何缩进
不要混合使用制表符和空格来缩进,因为这在跨越不同的平台的时候,无法正常工作。我 强
烈建议 你在每个缩进层次使用 单个制表符 或 两个或四个空格 。
选择这三种缩进风格之一。更加重要的是,选择一种风格,然后一贯地使用它,即 只 使用这
一种风格。
上一页 上一级 下一页
逻辑行与物理行 首页 概括
39. 简明 Python 教程
第6章 控制流
上一页 if语句 下一页
if语句
if语句用来检验一个条件, 如果 条件为真,我们运行一块语句(称为 if-块 ), 否则 我们处理
另外一块语句(称为 else-块 )。 else 从句是可选的。
使用if语句
例6.1 使用if语句
#!/usr/bin/python
# Filename: if.py
number = 23
guess = int(raw_input('Enter an integer : '))
if guess == number:
print 'Congratulations, you guessed it.' # New block starts here
print "(but you do not win any prizes!)" # New block ends here
elif guess < number:
print 'No, it is a little higher than that' # Another block
# You can do whatever you want in a block ...
else:
print 'No, it is a little lower than that'
# you must have guess > number to reach here
print 'Done'
# This last statement is always executed, after the if statement is executed
(源文件:code/if.py)
输出
$ python if.py
Enter an integer : 50
No, it is a little lower than that
Done
$ python if.py
Enter an integer : 22
No, it is a little higher than that
Done
$ python if.py
Enter an integer : 23
Congratulations, you guessed it.
(but you do not win any prizes!)
Done
它如何工作
在这个程序中,我们从用户处得到猜测的数,然后检验这个数是否是我们手中的那个。我们把
变量number设置为我们想要的任何整数,在这个例子中是23。然后,我们使用raw_input()函数
取得用户猜测的数字。函数只是重用的程序段。我们将在下一章学习更多关于函数的知识。
我们为内建的raw_input函数提供一个字符串,这个字符串被打印在屏幕上,然后等待用户的输
入。一旦我们输入一些东西,然后按回车键之后,函数返回输入。对于raw_input函数来说是一
个字符串。我们通过int把这个字符串转换为整数,并把它存储在变量guess中。事实上,int是
一个类,不过你想在对它所需了解的只是它把一个字符串转换为一个整数(假设这个字符串含
有一个有效的整数文本信息)。
接下来,我们将用户的猜测与我们选择的数做比较。如果他们相等,我们打印一个成功的消
息。注意我们使用了缩进层次来告诉Python每个语句分别属于哪一个块。这就是为什么缩进在
Python如此重要的原因。我希望你能够坚持“每个缩进层一个制表符”的规则。你是这样的
吗?
注意if语句在结尾处包含一个冒号——我们通过它告诉Python下面跟着一个语句块。
然后,我们检验猜测是否小于我们的数,如果是这样的,我们告诉用户它的猜测大了一点。我
们在这里使用的是elif从句,它事实上把两个相关联的if else-if else语句合并为一个if-elif-else语
句。这使得程序更加简单,并且减少了所需的缩进数量。
elif和else从句都必须在逻辑行结尾处有一个冒号,下面跟着一个相应的语句块(当然还包括正
确的缩进)。
你也可以在一个if块中使用另外一个if语句,等等——这被称为嵌套的if语句。
记住,elif和else部分是可选的。一个最简单的有效if语句是:
if True:
print 'Yes, it is true'
在Python执行完一个完整的if语句以及与它相关联的elif和else从句之后,它移向if语句块的下一
个语句。在这个例子中,这个语句块是主块。程序从主块开始执行,而下一个语句是print
'Done'语句。在这之后,Python看到程序的结尾,简单的结束运行。
尽管这是一个非常简单的程序,但是我已经在这个简单的程序中指出了许多你应该注意的地
方。所有这些都是十分直接了当的(对于那些拥有C/C++背景的用户来说是尤为简单的)。它
们在开始时会引起你的注意,但是以后你会对它们感到熟悉、“自然”。
给C/C++程序员的注释
在Python中没有switch语句。你可以使用if..elif..else语句来完成同样的工作(在某些场合,使用
字典会更加快捷。)
上一页 上一级 下一页
简介 首页 while语句
40. 简明 Python 教程
第6章 控制流
上一页 while语句 下一页
while语句
只要在一个条件为真的情况下,while语句允许你重复执行一块语句。while语句是所谓 循环 语
句的一个例子。while语句有一个可选的else从句。
使用while语句
例6.2 使用while语句
#!/usr/bin/python
# Filename: while.py
number = 23
running = True
while running:
guess = int(raw_input('Enter an integer : '))
if guess == number:
print 'Congratulations, you guessed it.'
running = False # this causes the while loop to stop
elif guess < number:
print 'No, it is a little higher than that'
else:
print 'No, it is a little lower than that'
else:
print 'The while loop is over.'
# Do anything else you want to do here
print 'Done'
(源文件:code/while.py)
输出
$ python while.py
Enter an integer : 50
No, it is a little lower than that.
Enter an integer : 22
No, it is a little higher than that.
Enter an integer : 23
Congratulations, you guessed it.
The while loop is over.
Done
它如何工作
在这个程序中,我们仍然使用了猜数游戏作为例子,但是这个例子的优势在于用户可以不断的
猜数,直到他猜对为止——这样就不需要像前面那个例子那样为每次猜测重复执行一遍程序。
这个例子恰当地说明了while语句的使用。
我们把raw_input和if语句移到了while循环内,并且在while循环开始前把running变量设置为
True。首先,我们检验变量running是否为True,然后执行后面的 while-块 。在执行了这块程序
之后,再次检验条件,在这个例子中,条件是running变量。如果它是真的,我们再次执行
while-块,否则,我们继续执行可选的else-块,并接着执行下一个语句。
当while循环条件变为False的时候,else块才被执行——这甚至也可能是在条件第一次被检验的
时候。如果while循环有一个else从句,它将始终被执行,除非你的while循环将永远循环下去不
会结束!
True和False被称为布尔类型。你可以分别把它们等效地理解为值1和0。在检验重要条件的时
候,布尔类型十分重要,它们并不是真实的值1。
else块事实上是多余的,因为你可以把其中的语句放在同一块(与while相同)中,跟在while语
句之后,这样可以取得相同的效果。
给C/C++程序员的注释
记住,你可以在while循环中使用一个else从句。
上一页 上一级 下一页
if语句 首页 for循环
41. 简明 Python 教程
第6章 控制流
上一页 for循环 下一页
for循环
for..in是另外一个循环语句,它在一序列的对象上 递归 即逐一使用队列中的每个项目。我们会
在后面的章节中更加详细地学习序列。
使用for语句
例6.3 使用for语句
#!/usr/bin/python
# Filename: for.py
for i in range(1, 5):
print i
else:
print 'The for loop is over'
输出
$ python for.py
1
2
3
4
The for loop is over
它如何工作
在这个程序中,我们打印了一个 序列 的数。我们使用内建的range函数生成这个数的序列。
我们所做的只是提供两个数,range返回一个序列的数。这个序列从第一个数开始到第二个数
为止。例如,range(1,5)给出序列[1, 2, 3, 4]。默认地,range的步长为1。如果我们为range提供第
三个数,那么它将成为步长。例如,range(1,5,2)给出[1,3]。记住,range 向上 延伸到第二个
数,即它不包含第二个数。
for循环在这个范围内递归——for i in range(1,5)等价于for i in [1, 2, 3, 4],这就如同把序列中的每
个数(或对象)赋值给i,一次一个,然后以每个i的值执行这个程序块。在这个例子中,我们
只是打印i的值。
记住,else部分是可选的。如果包含else,它总是在for循环结束后执行一次,除非遇到break语
句。
记住,for..in循环对于任何序列都适用。这里我们使用的是一个由内建range函数生成的数的列
表,但是广义说来我们可以使用任何种类的由任何对象组成的序列!我们会在后面的章节中详
细探索这个观点。
给C/C++/Java/C#程序员的注释
Python的for循环从根本上不同于C/C++的for循环。C#程序员会注意到Python的for循环与C#中
的foreach循环十分类似。Java程序员会注意到它与Java 1.5中的for (int i : IntArray)相似。
在C/C++中,如果你想要写for (int i = 0; i < 5; i++),那么用Python,你写成for i in range(0,5)。你
会注意到,Python的for循环更加简单、明白、不易出错。
上一页 上一级 下一页
while语句 首页 break语句
42. 简明 Python 教程
第6章 控制流
上一页 break语句 下一页
break语句
break语句是用来 终止 循环语句的,即哪怕循环条件没有称为False或序列还没有被完全递归,
也停止执行循环语句。
一个重要的注释是,如果你从for或while循环中 终止 ,任何对应的循环else块将不执行。
使用break语句
例6.4 使用break语句
#!/usr/bin/python
# Filename: break.py
while True:
s = raw_input('Enter something : ')
if s == 'quit':
break
print 'Length of the string is', len(s)
print 'Done'
(源文件:code/break.py)
输出
$ python break.py
Enter something : Programming is fun
Length of the string is 18
Enter something : When the work is done
Length of the string is 21
Enter something : if you wanna make your work also fun:
Length of the string is 37
Enter something : use Python!
Length of the string is 12
Enter something : quit
Done
它如何工作
在这个程序中,我们反复地取得用户地输入,然后打印每次输入地长度。我们提供了一个特别
的条件来停止程序,即检验用户的输入是否是'quit'。通过 终止 循环到达程序结尾来停止程
序。
输入字符串的长度通过内建的len函数取得。
记住,break语句也可以在for循环中使用。
G2的Python诗
我在这里输入的是我所写的一段小诗,称为G2的Python诗:
Programming is fun
When the work is done
if you wanna make your work also fun:
use Python!
上一页 上一级 下一页
for循环 首页 continue语句
43. 简明 Python 教程
第6章 控制流
上一页 continue语句 下一页
continue语句
continue语句被用来告诉Python跳过当前循环块中的剩余语句,然后 继续 进行下一轮循环。
使用continue语句
例6.5 使用continue语句
#!/usr/bin/python
# Filename: continue.py
while True:
s = raw_input('Enter something : ')
if s == 'quit':
break
if len(s) < 3:
continue
print 'Input is of sufficient length'
# Do other kinds of processing here...
(源文件:code/continue.py)
输出
$ python continue.py
Enter something : a
Enter something : 12
Enter something : abc
Input is of sufficient length
Enter something : quit
它如何工作
在这个程序中,我们从用户处取得输入,但是我们仅仅当它们有至少3个字符长的时候才处理
它们。所以,我们使用内建的len函数来取得长度。如果长度小于3,我们将使用continue语句
忽略块中的剩余的语句。否则,这个循环中的剩余语句将被执行,我们可以在这里做我们希望
的任何处理。
注意,continue语句对于for循环也有效。
上一页 上一级 下一页
break语句 首页 概括
46. 简明 Python 教程
第7章 函数
上一页 函数形参 下一页
函数形参
函数取得的参数是你提供给函数的值,这样函数就可以利用这些值 做 一些事情。这些参数就
像变量一样,只不过它们的值是在我们调用函数的时候定义的,而非在函数本身内赋值。
参数在函数定义的圆括号对内指定,用逗号分割。当我们调用函数的时候,我们以同样的方式
提供值。注意我们使用过的术语——函数中的参数名称为 形参 而你提供给函数调用的值称为
实参 。
使用函数形参
例7.2 使用函数形参
#!/usr/bin/python
# Filename: func_param.py
def printMax(a, b):
if a > b:
print a, 'is maximum'
else:
print b, 'is maximum'
printMax(3, 4) # directly give literal values
x=5
y=7
printMax(x, y) # give variables as arguments
(源文件:code/func_param.py)
输出
$ python func_param.py
4 is maximum
7 is maximum
它如何工作
这里,我们定义了一个称为printMax的函数,这个函数需要两个形参,叫做a和b。我们使用if..
else语句找出两者之中较大的一个数,并且打印较大的那个数。
在第一个printMax使用中,我们直接把数,即实参,提供给函数。在第二个使用中,我们使用
变量调用函数。printMax(x, y)使实参x的值赋给形参a,实参y的值赋给形参b。在两次调用中,
printMax函数的工作完全相同。
上一页 上一级 下一页
简介 首页 局部变量
47. 简明 Python 教程
第7章 函数
上一页 局部变量 下一页
局部变量
当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即
变量名称对于函数来说是 局部 的。这称为变量的 作用域 。所有变量的作用域是它们被定义的
块,从它们的名称被定义的那点开始。
使用局部变量
例7.3 使用局部变量
#!/usr/bin/python
# Filename: func_local.py
def func(x):
print 'x is', x
x=2
print 'Changed local x to', x
x = 50
func(x)
print 'x is still', x
(源文件:code/func_local.py)
输出
$ python func_local.py
x is 50
Changed local x to 2
x is still 50
它如何工作
在函数中,我们第一次使用x的 值 的时候,Python使用函数声明的形参的值。
接下来,我们把值2赋给x。x是函数的局部变量。所以,当我们在函数内改变x的值的时候,在
主块中定义的x不受影响。
在最后一个print语句中,我们证明了主块中的x的值确实没有受到影响。
使用global语句
如果你想要为一个定义在函数外的变量赋值,那么你就得告诉Python这个变量名不是局部的,
而是 全局 的。我们使用global语句完成这一功能。没有global语句,是不可能为定义在函数外
的变量赋值的。
你可以使用定义在函数外的变量的值(假设在函数内没有同名的变量)。然而,我并不鼓励你
这样做,并且你应该尽量避免这样做,因为这使得程序的读者会不清楚这个变量是在哪里定义
的。使用global语句可以清楚地表明变量是在外面的块定义的。
例7.4 使用global语句
#!/usr/bin/python
# Filename: func_global.py
def func():
global x
print 'x is', x
x=2
print 'Changed local x to', x
x = 50
func()
print 'Value of x is', x
(源文件:code/func_global.py)
输出
$ python func_global.py
x is 50
Changed global x to 2
Value of x is 2
它如何工作
global语句被用来声明x是全局的——因此,当我们在函数内把值赋给x的时候,这个变化也反
映在我们在主块中使用x的值的时候。
你可以使用同一个global语句指定多个全局变量。例如global x, y, z。
上一页 上一级 下一页
函数形参 首页 默认参数值
49. 简明 Python 教程
第7章 函数
上一页 关键参数 下一页
关键参数
如果你的某个函数有许多参数,而你只想指定其中的一部分,那么你可以通过命名来为这些参
数赋值——这被称作 关键参数 ——我们使用名字(关键字)而不是位置(我们前面所一直使
用的方法)来给函数指定实参。
这样做有两个 优势 ——一,由于我们不必担心参数的顺序,使用函数变得更加简单了。二、
假设其他参数都有默认值,我们可以只给我们想要的那些参数赋值。
使用关键参数
例7.6 使用关键参数
#!/usr/bin/python
# Filename: func_key.py
def func(a, b=5, c=10):
print 'a is', a, 'and b is', b, 'and c is', c
func(3, 7)
func(25, c=24)
func(c=50, a=100)
(源文件:code/func_key.py)
输出
$ python func_key.py
a is 3 and b is 7 and c is 10
a is 25 and b is 5 and c is 24
a is 100 and b is 5 and c is 50
它如何工作
名为func的函数有一个没有默认值的参数,和两个有默认值的参数。
在第一次使用函数的时候, func(3, 7),参数a得到值3,参数b得到值7,而参数c使用默认值
10。
在第二次使用函数func(25, c=24)的时候,根据实参的位置变量a得到值25。根据命名,即关键
参数,参数c得到值24。变量b根据默认值,为5。
在第三次使用func(c=50, a=100)的时候,我们使用关键参数来完全指定参数值。注意,尽管函
数定义中,a在c之前定义,我们仍然可以在a之前指定参数c的值。
上一页 上一级 下一页
默认参数值 首页 return语句
51. 简明 Python 教程
第7章 函数
上一页 DocStrings 下一页
DocStrings
Python有一个很奇妙的特性,称为 文档字符串 ,它通常被简称为 docstrings 。DocStrings是一个
重要的工具,由于它帮助你的程序文档更加简单易懂,你应该尽量使用它。你甚至可以在程序
运行的时候,从函数恢复文档字符串!
使用DocStrings
例7.8 使用DocStrings
#!/usr/bin/python
# Filename: func_doc.py
def printMax(x, y):
'''Prints the maximum of two numbers.
The two values must be integers.'''
x = int(x) # convert to integers, if possible
y = int(y)
if x > y:
print x, 'is maximum'
else:
print y, 'is maximum'
printMax(3, 5)
print printMax.__doc__
(源文件:code/func_doc.py)
输出
$ python func_doc.py
5 is maximum
Prints the maximum of two numbers.
The two values must be integers.
它如何工作
在函数的第一个逻辑行的字符串是这个函数的 文档字符串 。注意,DocStrings也适用于模块和
类,我们会在后面相应的章节学习它们。
文档字符串的惯例是一个多行字符串,它的首行以大写字母开始,句号结尾。第二行是空行,
从第三行开始是详细的描述。 强烈建议 你在你的函数中使用文档字符串时遵循这个惯例。
你可以使用__doc__(注意双下划线)调用printMax函数的文档字符串属性(属于函数的名
称)。请记住Python把 每一样东西 都作为对象,包括这个函数。我们会在后面的类一章学习
更多关于对象的知识。
如果你已经在Python中使用过help(),那么你已经看到过DocStings的使用了!它所做的只是抓
取函数的__doc__属性,然后整洁地展示给你。你可以对上面这个函数尝试一下——只是在你
的程序中包括help(printMax)。记住按q退出help。
自动化工具也可以以同样的方式从你的程序中提取文档。因此,我 强烈建议 你对你所写的任
何正式函数编写文档字符串。随你的Python发行版附带的pydoc命令,与help()类似地使用
DocStrings。
上一页 上一级 下一页
return语句 首页 概括
56. 简明 Python 教程
第8章 模块
上一页 模块的__name__ 下一页
模块的__name__
每个模块都有一个名称,在模块中可以通过语句来找出模块的名称。这在一个场合特别有用
——就如前面所提到的,当一个模块被第一次输入的时候,这个模块的主块将被运行。假如我
们只想在程序本身被使用的时候运行主块,而在它被别的模块输入的时候不运行主块,我们该
怎么做呢?这可以通过模块的__name__属性完成。
使用模块的__name__
例8.2 使用模块的__name__
#!/usr/bin/python
# Filename: using_name.py
if __name__ == '__main__':
print 'This program is being run by itself'
else:
print 'I am being imported from another module'
(源文件:code/using_name.py)
输出
$ python using_name.py
This program is being run by itself
$ python
>>> import using_name
I am being imported from another module
>>>
它如何工作
每个Python模块都有它的__name__,如果它是'__main__',这说明这个模块被用户单独运行,
我们可以进行相应的恰当操作。
上一页 上一级 下一页
制造你自己的模
from..import语句 首页
块
57. 简明 Python 教程
第8章 模块
上一页 制造你自己的模块 下一页
制造你自己的模块
创建你自己的模块是十分简单的,你一直在这样做!每个Python程序也是一个模块。你已经确
保它具有.py扩展名了。下面这个例子将会使它更加清晰。
创建你自己的模块
例8.3 如何创建你自己的模块
#!/usr/bin/python
# Filename: mymodule.py
def sayhi():
print 'Hi, this is mymodule speaking.'
version = '0.1'
# End of mymodule.py
(源文件:code/mymodule.py)
上面是一个 模块 的例子。你已经看到,它与我们普通的Python程序相比并没有什么特别之
处。我们接下来将看看如何在我们别的Python程序中使用这个模块。
记住这个模块应该被放置在我们输入它的程序的同一个目录中,或者在sys.path所列目录之
一。
#!/usr/bin/python
# Filename: mymodule_demo.py
import mymodule
mymodule.sayhi()
print 'Version', mymodule.version
(源文件:code/mymodule_demo.py)
输出
$ python mymodule_demo.py
Hi, this is mymodule speaking.
Version 0.1
它如何工作
注意我们使用了相同的点号来使用模块的成员。Python很好地重用了相同的记号来,使我们这
些Python程序员不需要不断地学习新的方法。
from..import
下面是一个使用from..import语法的版本。
#!/usr/bin/python
# Filename: mymodule_demo2.py
from mymodule import sayhi, version
# Alternative:
# from mymodule import *
sayhi()
print 'Version', version
(源文件:code/mymodule_demo2.py)
mymodule_demo2.py的输出与mymodule_demo.py完全相同。
上一页 上一级 下一页
模块的__name__ 首页 dir()函数
58. 简明 Python 教程
第8章 模块
上一页 dir()函数 下一页
dir()函数
你可以使用内建的dir函数来列出模块定义的标识符。标识符有函数、类和变量。
当你为dir()提供一个模块名的时候,它返回模块定义的名称列表。如果不提供参数,它返回当
前模块中定义的名称列表。
使用dir函数
例8.4 使用dir函数
$ python
>>> import sys
>>> dir(sys) # get list of attributes for sys module
['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__',
'__stdin__', '__stdout__', '_getframe', 'api_version', 'argv',
'builtin_module_names', 'byteorder', 'call_tracing', 'callstats',
'copyright', 'displayhook', 'exc_clear', 'exc_info', 'exc_type',
'excepthook', 'exec_prefix', 'executable', 'exit', 'getcheckinterval',
'getdefaultencoding', 'getdlopenflags', 'getfilesystemencoding',
'getrecursionlimit', 'getrefcount', 'hexversion', 'maxint', 'maxunicode',
'meta_path','modules', 'path', 'path_hooks', 'path_importer_cache',
'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags',
'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout',
'version', 'version_info', 'warnoptions']
>>> dir() # get list of attributes for current module
['__builtins__', '__doc__', '__name__', 'sys']
>>>
>>> a = 5 # create a new variable 'a'
>>> dir()
['__builtins__', '__doc__', '__name__', 'a', 'sys']
>>>
>>> del a # delete/remove a name
>>>
>>> dir()
['__builtins__', '__doc__', '__name__', 'sys']
>>>
它如何工作
首先,我们来看一下在输入的sys模块上使用dir。我们看到它包含一个庞大的属性列表。
接下来,我们不给dir函数传递参数而使用它——默认地,它返回当前模块的属性列表。注
意,输入的模块同样是列表的一部分。
为了观察dir的作用,我们定义一个新的变量a并且给它赋一个值,然后检验dir,我们观察到在
列表中增加了以上相同的值。我们使用del语句删除当前模块中的变量/属性,这个变化再一次
反映在dir的输出中。
关于del的一点注释——这个语句在运行后被用来 删除 一个变量/名称。在这个例子中,del a,
你将无法再使用变量a——它就好像从来没有存在过一样。
上一页 上一级 下一页
制造你自己的模
首页 概括
块
61. 简明 Python 教程
第9章 数据结构
上一页 列表 下一页
列表
list是处理一组有序项目的数据结构,即你可以在一个列表中存储一个 序列 的项目。假想你有
一个购物列表,上面记载着你要买的东西,你就容易理解列表了。只不过在你的购物表上,可
能每样东西都独自占有一行,而在Python中,你在每个项目之间用逗号分割。
列表中的项目应该包括在方括号中,这样Python就知道你是在指明一个列表。一旦你创建了一
个列表,你可以添加、删除或是搜索列表中的项目。由于你可以增加或删除项目,我们说列表
是 可变的 数据类型,即这种类型是可以被改变的。
对象与类的快速入门
尽管我一直推迟讨论对象和类,但是现在对它们做一点解释可以使你更好的理解列表。我们会
在相应的章节详细探索这个主题。
列表是使用对象和类的一个例子。当你使用变量i并给它赋值的时候,比如赋整数5,你可以认
为你创建了一个类(类型)int的对象(实例)i。事实上,你可以看一下help(int)以更好地理解
这一点。
类也有方法,即仅仅为类而定义地函数。仅仅在你有一个该类的对象的时候,你才可以使用这
些功能。例如,Python为list类提供了append方法,这个方法让你在列表尾添加一个项目。例如
mylist.append('an item')列表mylist中增加那个字符串。注意,使用点号来使用对象的方法。
一个类也有域,它是仅仅为类而定义的变量。仅仅在你有一个该类的对象的时候,你才可以使
用这些变量/名称。类也通过点号使用,例如mylist.field。
使用列表
例9.1 使用列表
#!/usr/bin/python
# Filename: using_list.py
# This is my shopping list
shoplist = ['apple', 'mango', 'carrot', 'banana']
print 'I have', len(shoplist),'items to purchase.'
print 'These items are:', # Notice the comma at end of the line
for item in shoplist:
print item,
print 'nI also have to buy rice.'
shoplist.append('rice')
print 'My shopping list is now', shoplist
print 'I will sort my list now'
shoplist.sort()
print 'Sorted shopping list is', shoplist
print 'The first item I will buy is', shoplist[0]
olditem = shoplist[0]
del shoplist[0]
print 'I bought the', olditem
print 'My shopping list is now', shoplist
(源文件:code/using_list.py)
输出
$ python using_list.py
I have 4 items to purchase.
These items are: apple mango carrot banana
I also have to buy rice.
My shopping list is now ['apple', 'mango', 'carrot', 'banana', 'rice']
I will sort my list now
Sorted shopping list is ['apple', 'banana', 'carrot', 'mango', 'rice']
The first item I will buy is apple
I bought the apple
My shopping list is now ['banana', 'carrot', 'mango', 'rice']
它如何工作
变量shoplist是某人的购物列表。在shoplist中,我们只存储购买的东西的名字字符串,但是记
住,你可以在列表中添加 任何种类的对象 包括数甚至其他列表。
我们也使用了for..in循环在列表中各项目间递归。从现在开始,你一定已经意识到列表也是一
个序列。序列的特性会在后面的章节中讨论。
注意,我们在print语句的结尾使用了一个 逗号 来消除每个print语句自动打印的换行符。这样
做有点难看,不过确实简单有效。
接下来,我们使用append方法在列表中添加了一个项目,就如前面已经讨论过的一样。然后我
们通过打印列表的内容来检验这个项目是否确实被添加进列表了。打印列表只需简单地把列表
传递给print语句,我们可以得到一个整洁的输出。
再接下来,我们使用列表的sort方法来对列表排序。需要理解的是,这个方法影响列表本身,
而不是返回一个修改后的列表——这与字符串工作的方法不同。这就是我们所说的列表是 可
变的 而字符串是 不可变的 。
最后,但我们完成了在市场购买一样东西的时候,我们想要把它从列表中删除。我们使用del
语句来完成这个工作。这里,我们指出我们想要删除列表中的哪个项目,而del语句为我们从
列表中删除它。我们指明我们想要删除列表中的第一个元素,因此我们使用del shoplist[0](记
住,Python从0开始计数)。
如果你想要知道列表对象定义的所有方法,可以通过help(list)获得完整的知识。
上一页 上一级 下一页
简介 首页 元组
62. 简明 Python 教程
第9章 数据结构
上一页 元组 下一页
元组
元组和列表十分类似,只不过元组和字符串一样是 不可变的 即你不能修改元组。元组通过圆
括号中用逗号分割的项目定义。元组通常用在使语句或用户定义的函数能够安全地采用一组值
的时候,即被使用的元组的值不会改变。
使用元组
例9.2 使用元组
#!/usr/bin/python
# Filename: using_tuple.py
zoo = ('wolf', 'elephant', 'penguin')
print 'Number of animals in the zoo is', len(zoo)
new_zoo = ('monkey', 'dolphin', zoo)
print 'Number of animals in the new zoo is', len(new_zoo)
print 'All animals in new zoo are', new_zoo
print 'Animals brought from old zoo are', new_zoo[2]
print 'Last animal brought from old zoo is', new_zoo[2][2]
(源文件:code/using_tuple.py)
输出
$ python using_tuple.py
Number of animals in the zoo is 3
Number of animals in the new zoo is 3
All animals in new zoo are ('monkey', 'dolphin', ('wolf', 'elephant', 'penguin'))
Animals brought from old zoo are ('wolf', 'elephant', 'penguin')
Last animal brought from old zoo is penguin
它如何工作
变量zoo是一个元组,我们看到len函数可以用来获取元组的长度。这也表明元组也是一个序
列。
由于老动物园关闭了,我们把动物转移到新动物园。因此,new_zoo元组包含了一些已经在那
里的动物和从老动物园带过来的动物。回到话题,注意元组之内的元组不会失去它的身份。
我们可以通过一对方括号来指明某个项目的位置从而来访问元组中的项目,就像我们对列表的
用法一样。这被称作 索引 运算符。我们使用new_zoo[2]来访问new_zoo中的第三个项目。我们
使用new_zoo[2][2]来访问new_zoo元组的第三个项目的第三个项目。
含有0个或1个项目的元组。一个空的元组由一对空的圆括号组成,如myempty = ()。然而,含
有单个元素的元组就不那么简单了。你必须在第一个(唯一一个)项目后跟一个逗号,这样
Python才能区分元组和表达式中一个带圆括号的对象。即如果你想要的是一个包含项目2的元
组的时候,你应该指明singleton = (2 , )。
给Perl程序员的注释
列表之中的列表不会失去它的身份,即列表不会像Perl中那样被打散。同样元组中的元组,或
列表中的元组,或元组中的列表等等都是如此。只要是Python,它们就只是使用另一个对象存
储的对象。
元组与打印语句
元组最通常的用法是用在打印语句中,下面是一个例子:
例9.3 使用元组输出
#!/usr/bin/python
# Filename: print_tuple.py
age = 22
name = 'Swaroop'
print '%s is %d years old' % (name, age)
print 'Why is %s playing with that python?' % name
(源文件:code/print_tuple.py)
输出
$ python print_tuple.py
Swaroop is 22 years old
Why is Swaroop playing with that python?
它如何工作
print语句可以使用跟着%符号的项目元组的字符串。这些字符串具备定制的功能。定制让输出
满足某种特定的格式。定制可以是%s表示字符串或%d表示整数。元组必须按照相同的顺序来
对应这些定制。
观察我们使用的第一个元组,我们首先使用%s,这对应变量name,它是元组中的第一个项
目。而第二个定制是%d,它对应元组的第二个项目age。
Python在这里所做的是把元组中的每个项目转换成字符串并且用字符串的值替换定制的位置。
因此%s被替换为变量name的值,依此类推。
print的这个用法使得编写输出变得极其简单,它避免了许多字符串操作。它也避免了我们一直
以来使用的逗号。
在大多数时候,你可以只使用%s定制,而让Python来提你处理剩余的事情。这种方法对数同样
奏效。然而,你可能希望使用正确的定制,从而可以避免多一层的检验程序是否正确。
在第二个print语句中,我们使用了一个定制,后面跟着%符号后的单个项目——没有圆括号。
这只在字符串中只有一个定制的时候有效。
上一页 上一级 下一页
列表 首页 字典
63. 简明 Python 教程
第9章 数据结构
上一页 字典 下一页
字典
字典类似于你通过联系人名字查找地址和联系人详细情况的地址簿,即,我们把键(名字)和
值(详细情况)联系在一起。注意,键必须是唯一的,就像如果有两个人恰巧同名的话,你无
法找到正确的信息。
注意,你只能使用不可变的对象(比如字符串)来作为字典的键,但是你可以把不可变或可变
的对象作为字典的值。基本说来就是,你应该只使用简单的对象作为键。
键值对在字典中以这样的方式标记:d = {key1 : value1, key2 : value2 }。注意它们的键/值对用冒
号分割,而各个对用逗号分割,所有这些都包括在花括号中。
记住字典中的键/值对是没有顺序的。如果你想要一个特定的顺序,那么你应该在使用前自己
对它们排序。
字典是dict类的实例/对象。
使用字典
例9.4 使用字典
#!/usr/bin/python
# Filename: using_dict.py
# 'ab' is short for 'a'ddress'b'ook
ab = { 'Swaroop' : 'swaroopch@byteofpython.info',
'Larry' : 'larry@wall.org',
'Matsumoto' : 'matz@ruby-lang.org',
'Spammer' : 'spammer@hotmail.com'
}
print "Swaroop's address is %s" % ab['Swaroop']
# Adding a key/value pair
ab['Guido'] = 'guido@python.org'
# Deleting a key/value pair
del ab['Spammer']
print 'nThere are %d contacts in the address-bookn' % len(ab)
for name, address in ab.items():
print 'Contact %s at %s' % (name, address)
if 'Guido' in ab: # OR ab.has_key('Guido')
print "nGuido's address is %s" % ab['Guido']
(源文件:code/using_dict.py)
输出
$ python using_dict.py
Swaroop's address is swaroopch@byteofpython.info
There are 4 contacts in the address-book
Contact Swaroop at swaroopch@byteofpython.info
Contact Matsumoto at matz@ruby-lang.org
Contact Larry at larry@wall.org
Contact Guido at guido@python.org
Guido's address is guido@python.org
它如何工作
我们使用已经介绍过的标记创建了字典ab。然后我们使用在列表和元组章节中已经讨论过的索
引操作符来指定键,从而使用键/值对。我们可以看到字典的语法同样十分简单。
我们可以使用索引操作符来寻址一个键并为它赋值,这样就增加了一个新的键/值对,就像在
上面的例子中我们对Guido所做的一样。
我们可以使用我们的老朋友——del语句来删除键/值对。我们只需要指明字典和用索引操作符
指明要删除的键,然后把它们传递给del语句就可以了。执行这个操作的时候,我们无需知道
那个键所对应的值。
接下来,我们使用字典的items方法,来使用字典中的每个键/值对。这会返回一个元组的列
表,其中每个元组都包含一对项目——键与对应的值。我们抓取这个对,然后分别赋给for..in
循环中的变量name和address然后在for-块中打印这些值。
我们可以使用in操作符来检验一个键/值对是否存在,或者使用dict类的has_key方法。你可以使
用help(dict)来查看dict类的完整方法列表。
关键字参数与字典。如果换一个角度看待你在函数中使用的关键字参数的话,你已经使用了字
典了!只需想一下——你在函数定义的参数列表中使用的键/值对。当你在函数中使用变量的
时候,它只不过是使用一个字典的键(这在编译器设计的术语中被称作 符号表 )。
上一页 上一级 下一页
元组 首页 序列
64. 简明 Python 教程
第9章 数据结构
上一页 序列 下一页
序列
列表、元组和字符串都是序列,但是序列是什么,它们为什么如此特别呢?序列的两个主要特
点是索引操作符和切片操作符。索引操作符让我们可以从序列中抓取一个特定项目。切片操作
符让我们能够获取序列的一个切片,即一部分序列。
使用序列
例9.5 使用序列
#!/usr/bin/python
# Filename: seq.py
shoplist = ['apple', 'mango', 'carrot', 'banana']
# Indexing or 'Subscription' operation
print 'Item 0 is', shoplist[0]
print 'Item 1 is', shoplist[1]
print 'Item 2 is', shoplist[2]
print 'Item 3 is', shoplist[3]
print 'Item -1 is', shoplist[-1]
print 'Item -2 is', shoplist[-2]
# Slicing on a list
print 'Item 1 to 3 is', shoplist[1:3]
print 'Item 2 to end is', shoplist[2:]
print 'Item 1 to -1 is', shoplist[1:-1]
print 'Item start to end is', shoplist[:]
# Slicing on a string
name = 'swaroop'
print 'characters 1 to 3 is', name[1:3]
print 'characters 2 to end is', name[2:]
print 'characters 1 to -1 is', name[1:-1]
print 'characters start to end is', name[:]
(源文件:code/seq.py)
输出
$ python seq.py
Item 0 is apple
Item 1 is mango
Item 2 is carrot
Item 3 is banana
Item -1 is banana
Item -2 is carrot
Item 1 to 3 is ['mango', 'carrot']
Item 2 to end is ['carrot', 'banana']
Item 1 to -1 is ['mango', 'carrot']
Item start to end is ['apple', 'mango', 'carrot', 'banana']
characters 1 to 3 is wa
characters 2 to end is aroop
characters 1 to -1 is waroo
characters start to end is swaroop
它如何工作
首先,我们来学习如何使用索引来取得序列中的单个项目。这也被称作是下标操作。每当你用
方括号中的一个数来指定一个序列的时候,Python会为你抓取序列中对应位置的项目。记住,
Python从0开始计数。因此,shoplist[0]抓取第一个项目,shoplist[3]抓取shoplist序列中的第四个
元素。
索引同样可以是负数,在那样的情况下,位置是从序列尾开始计算的。因此,shoplist[-1]表示
序列的最后一个元素而shoplist[-2]抓取序列的倒数第二个项目。
切片操作符是序列名后跟一个方括号,方括号中有一对可选的数字,并用冒号分割。注意这与
你使用的索引操作符十分相似。记住数是可选的,而冒号是必须的。
切片操作符中的第一个数(冒号之前)表示切片开始的位置,第二个数(冒号之后)表示切片
到哪里结束。如果不指定第一个数,Python就从序列首开始。如果没有指定第二个数,则
Python会停止在序列尾。注意,返回的序列从开始位置 开始 ,刚好在 结束 位置之前结束。即
开始位置是包含在序列切片中的,而结束位置被排斥在切片外。
这样,shoplist[1:3]返回从位置1开始,包括位置2,但是停止在位置3的一个序列切片,因此返
回一个含有两个项目的切片。类似地,shoplist[:]返回整个序列的拷贝。
你可以用负数做切片。负数用在从序列尾开始计算的位置。例如,shoplist[:-1]会返回除了最后
一个项目外包含所有项目的序列切片。
使用Python解释器交互地尝试不同切片指定组合,即在提示符下你能够马上看到结果。序列的
神奇之处在于你可以用相同的方法访问元组、列表和字符串。
上一页 上一级 下一页
字典 首页 引用
65. 简明 Python 教程
第9章 数据结构
上一页 引用 下一页
引用
当你创建一个对象并给它赋一个变量的时候,这个变量仅仅 引用 那个对象,而不是表示这个
对象本身!也就是说,变量名指向你计算机中存储那个对象的内存。这被称作名称到对象的绑
定。
一般说来,你不需要担心这个,只是在引用上有些细微的效果需要你注意。这会通过下面这个
例子加以说明。
对象与引用
例9.6 对象与引用
#!/usr/bin/python
# Filename: reference.py
print 'Simple Assignment'
shoplist = ['apple', 'mango', 'carrot', 'banana']
mylist = shoplist # mylist is just another name pointing to the same object!
del shoplist[0]
print 'shoplist is', shoplist
print 'mylist is', mylist
# notice that both shoplist and mylist both print the same list without
# the 'apple' confirming that they point to the same object
print 'Copy by making a full slice'
mylist = shoplist[:] # make a copy by doing a full slice
del mylist[0] # remove first item
print 'shoplist is', shoplist
print 'mylist is', mylist
# notice that now the two lists are different
(源文件:code/reference.py)
输出
$ python reference.py
Simple Assignment
shoplist is ['mango', 'carrot', 'banana']
mylist is ['mango', 'carrot', 'banana']
Copy by making a full slice
shoplist is ['mango', 'carrot', 'banana']
mylist is ['carrot', 'banana']
它如何工作
大多数解释已经在程序的注释中了。你需要记住的只是如果你想要复制一个列表或者类似的序
列或者其他复杂的对象(不是如整数那样的简单 对象 ),那么你必须使用切片操作符来取得
拷贝。如果你只是想要使用另一个变量名,两个名称都 引用 同一个对象,那么如果你不小心
的话,可能会引来各种麻烦。
给Perl程序员的注释
记住列表的赋值语句不创建拷贝。你得使用切片操作符来建立序列的拷贝。
上一页 上一级 下一页
更多字符串的内
序列 首页
容
66. 简明 Python 教程
第9章 数据结构
上一页 更多字符串的内容 下一页
更多字符串的内容
我们已经在前面详细讨论了字符串。我们还需要知道什么呢?那么,你是否知道字符串也是对
象,同样具有方法。这些方法可以完成包括检验一部分字符串和去除空格在内的各种工作。
你在程序中使用的字符串都是str类的对象。这个类的一些有用的方法会在下面这个例子中说
明。如果要了解这些方法的完整列表,请参见help(str)。
字符串的方法
例9.7 字符串的方法
#!/usr/bin/python
# Filename: str_methods.py
name = 'Swaroop' # This is a string object
if name.startswith('Swa'):
print 'Yes, the string starts with "Swa"'
if 'a' in name:
print 'Yes, it contains the string "a"'
if name.find('war') != -1:
print 'Yes, it contains the string "war"'
delimiter = '_*_'
mylist = ['Brazil', 'Russia', 'India', 'China']
print delimiter.join(mylist)
(源文件:code/str_methods.py)
输出
$ python str_methods.py
Yes, the string starts with "Swa"
Yes, it contains the string "a"
Yes, it contains the string "war"
Brazil_*_Russia_*_India_*_China
它如何工作
这里,我们看到使用了许多字符串方法。startwith方法是用来测试字符串是否以给定字符串开
始。in操作符用来检验一个给定字符串是否为另一个字符串的一部分。
find方法用来找出给定字符串在另一个字符串中的位置,或者返回-1以表示找不到子字符串。
str类也有以一个作为分隔符的字符串join序列的项目的整洁的方法,它返回一个生成的大字符
串。
上一页 上一级 下一页
引用 首页 概括
69. 简明 Python 教程
第10章 解决问题——编写一个Python脚本
上一页 解决方案 下一页
解决方案
当我们基本完成程序的设计,我们就可以编写代码了,它是对我们的解决方案的实施。
版本一
例10.1 备份脚本——版本一
#!/usr/bin/python
# Filename: backup_ver1.py
import os
import time
# 1. The files and directories to be backed up are specified in a list.
source = ['/home/swaroop/byte', '/home/swaroop/bin']
# If you are using Windows, use source = [r'C:Documents', r'D:Work'] or something like that
# 2. The backup must be stored in a main backup directory
target_dir = '/mnt/e/backup/' # Remember to change this to what you will be using
# 3. The files are backed up into a zip file.
# 4. The name of the zip archive is the current date and time
target = target_dir + time.strftime('%Y%m%d%H%M%S') + '.zip'
# 5. We use the zip command (in Unix/Linux) to put the files in a zip archive
zip_command = "zip -qr '%s' %s" % (target, ' '.join(source))
# Run the backup
if os.system(zip_command) == 0:
print 'Successful backup to', target
else:
print 'Backup FAILED'
(源文件:code/backup_ver1.py)
输出
$ python backup_ver1.py
Successful backup to /mnt/e/backup/20041208073244.zip
现在,我们已经处于测试环节了,在这个环节,我们测试我们的程序是否正确工作。如果它与
我们所期望的不一样,我们就得调试我们的程序,即消除程序中的 瑕疵 (错误)。
它如何工作
接下来你将看到我们如何把 设计 一步一步地转换为 代码 。
我们使用了os和time模块,所以我们输入它们。然后,我们在source列表中指定需要备份的文
件和目录。目标目录是我们想要存储备份文件的地方,它由target_dir变量指定。zip归档的名称
是目前的日期和时间,我们使用time.strftime()函数获得。它还包括.zip扩展名,将被保存在
target_dir目录中。
time.strftime()函数需要我们在上面的程序中使用的那种定制。%Y会被无世纪的年份所替代。%
m会被01到12之间的一个十进制月份数替代,其他依次类推。这些定制的详细情况可以在
《Python参考手册》中获得。《Python参考手册》包含在你的Python发行版中。注意这些定制
与用于print语句的定制(%后跟一个元组)类似(但不完全相同)
我们使用加法操作符来 级连 字符串,即把两个字符串连接在一起返回一个新的字符串。通过
这种方式,我们创建了目标zip文件的名称。接着我们创建了zip_command字符串,它包含我们
将要执行的命令。你可以在shell(Linux终端或者DOS提示符)中运行它,以检验它是否工作。
zip命令有一些选项和参数。-q选项用来表示zip命令安静地工作。-r选项表示zip命令对目录递
归地工作,即它包括子目录以及子目录中的文件。两个选项可以组合成缩写形式-qr。选项后
面跟着待创建的zip归档的名称,然后再是待备份的文件和目录列表。我们使用已经学习过的
字符串join方法把source列表转换为字符串。
最后,我们使用os.system函数 运行 命令,利用这个函数就好像在 系统 中运行命令一样。即在
shell中运行命令——如果命令成功运行,它返回0,否则它返回错误号。
根据命令的输出,我们打印对应的消息,显示备份是否创建成功。好了,就是这样我们已经创
建了一个脚本来对我们的重要文件做备份!
给Windows用户的注释
你可以把source列表和target目录设置成任何文件和目录名,但是在Windows中你得小心一些。
问题是Windows把反斜杠()作为目录分隔符,而Python用反斜杠表示转义符!
所以,你得使用转义符来表示反斜杠本身或者使用自然字符串。例如,使用'C:Documents'或
r'C:Documents'而不是'C:Documents'——你在使用一个不知名的转义符D!
现在我们已经有了一个可以工作的备份脚本,我们可以在任何我们想要建立文件备份的时候使
用它。建议Linux/Unix用户使用前面介绍的可执行的方法,这样就可以在任何地方任何时候运
行备份脚本了。这被称为软件的实施环节或开发环节。
上面的程序可以正确工作,但是(通常)第一个程序并不是与你所期望的完全一样。例如,可
能有些问题你没有设计恰当,又或者你在输入代码的时候发生了一点错误,等等。正常情况
下,你应该回到设计环节或者调试程序。
版本二
第一个版本的脚本可以工作。然而,我们可以对它做些优化以便让它在我们的日常工作中变得
更好。这称为软件的维护环节。
我认为优化之一是采用更好的文件名机制——使用 时间 作为文件名,而当前的 日期 作为目录
名,存放在主备份目录中。这样做的一个优势是你的备份会以等级结构存储,因此它就更加容
易管理了。另外一个优势是文件名的长度也可以变短。还有一个优势是采用各自独立的文件夹
可以帮助你方便地检验你是否在每一天创建了备份,因为只有在你创建了备份,才会出现那天
的目录。
例10.2 备份脚本——版本二
#!/usr/bin/python
# Filename: backup_ver2.py
import os
import time
# 1. The files and directories to be backed up are specified in a list.
source = ['/home/swaroop/byte', '/home/swaroop/bin']
# If you are using Windows, use source = [r'C:Documents', r'D:Work'] or something like that
# 2. The backup must be stored in a main backup directory
target_dir = '/mnt/e/backup/' # Remember to change this to what you will be using
# 3. The files are backed up into a zip file.
# 4. The current day is the name of the subdirectory in the main directory
today = target_dir + time.strftime('%Y%m%d')
# The current time is the name of the zip archive
now = time.strftime('%H%M%S')
# Create the subdirectory if it isn't already there
if not os.path.exists(today):
os.mkdir(today) # make directory
print 'Successfully created directory', today
# The name of the zip file
target = today + os.sep + now + '.zip'
# 5. We use the zip command (in Unix/Linux) to put the files in a zip archive
zip_command = "zip -qr '%s' %s" % (target, ' '.join(source))
# Run the backup
if os.system(zip_command) == 0:
print 'Successful backup to', target
else:
print 'Backup FAILED'
(源文件:code/backup_ver2.py)
输出
$ python backup_ver2.py
Successfully created directory /mnt/e/backup/20041208
Successful backup to /mnt/e/backup/20041208/080020.zip
$ python backup_ver2.py
Successful backup to /mnt/e/backup/20041208/080428.zip
它如何工作
两个程序的大部分是相同的。改变的部分主要是使用os.exists函数检验在主备份目录中是否有
以当前日期作为名称的目录。如果没有,我们使用os.mkdir函数创建。
注意os.sep变量的用法——这会根据你的操作系统给出目录分隔符,即在Linux、Unix下它
是'/',在Windows下它是'',而在Mac OS下它是':'。使用os.sep而非直接使用字符,会使我们的
程序具有移植性,可以在上述这些系统下工作。
版本三
第二个版本在我做较多备份的时候还工作得不错,但是如果有极多备份的时候,我发现要区分
每个备份是干什么的,会变得十分困难!例如,我可能对程序或者演讲稿做了一些重要的改
变,于是我想要把这些改变与zip归档的名称联系起来。这可以通过在zip归档名上附带一个用
户提供的注释来方便地实现。
例10.3 备份脚本——版本三(不工作!)
#!/usr/bin/python
# Filename: backup_ver3.py
import os
import time
# 1. The files and directories to be backed up are specified in a list.
source = ['/home/swaroop/byte', '/home/swaroop/bin']
# If you are using Windows, use source = [r'C:Documents', r'D:Work'] or something like that
# 2. The backup must be stored in a main backup directory
target_dir = '/mnt/e/backup/' # Remember to change this to what you will be using
# 3. The files are backed up into a zip file.
# 4. The current day is the name of the subdirectory in the main directory
today = target_dir + time.strftime('%Y%m%d')
# The current time is the name of the zip archive
now = time.strftime('%H%M%S')
# Take a comment from the user to create the name of the zip file
comment = raw_input('Enter a comment --> ')
if len(comment) == 0: # check if a comment was entered
target = today + os.sep + now + '.zip'
else:
target = today + os.sep + now + '_' +
comment.replace(' ', '_') + '.zip'
# Create the subdirectory if it isn't already there
if not os.path.exists(today):
os.mkdir(today) # make directory
print 'Successfully created directory', today
# 5. We use the zip command (in Unix/Linux) to put the files in a zip archive
zip_command = "zip -qr '%s' %s" % (target, ' '.join(source))
# Run the backup
if os.system(zip_command) == 0:
print 'Successful backup to', target
else:
print 'Backup FAILED'
(源文件:code/backup_ver3.py)
输出
$ python backup_ver3.py
File "backup_ver3.py", line 25
target = today + os.sep + now + '_' +
^
SyntaxError: invalid syntax
它如何(不)工作
这个程序不工作!Python说有一个语法错误,这意味着脚本不满足Python可以识别的结构。当
我们观察Python给出的错误的时候,它也告诉了我们它检测出错误的位置。所以我们从那行开
始 调试 我们的程序。
通过仔细的观察,我们发现一个逻辑行被分成了两个物理行,但是我们并没有指明这两个物理
行属于同一逻辑行。基本上,Python发现加法操作符(+)在那一逻辑行没有任何操作数,因
此它不知道该如何继续。记住我们可以使用物理行尾的反斜杠来表示逻辑行在下一物理行继
续。所以,我们修正了程序。这被称为修订。
版本四
例10.4 备份脚本——版本四
#!/usr/bin/python
# Filename: backup_ver4.py
import os
import time
# 1. The files and directories to be backed up are specified in a list.
source = ['/home/swaroop/byte', '/home/swaroop/bin']
# If you are using Windows, use source = [r'C:Documents', r'D:Work'] or something like that
# 2. The backup must be stored in a main backup directory
target_dir = '/mnt/e/backup/' # Remember to change this to what you will be using
# 3. The files are backed up into a zip file.
# 4. The current day is the name of the subdirectory in the main directory
today = target_dir + time.strftime('%Y%m%d')
# The current time is the name of the zip archive
now = time.strftime('%H%M%S')
# Take a comment from the user to create the name of the zip file
comment = raw_input('Enter a comment --> ')
if len(comment) == 0: # check if a comment was entered
target = today + os.sep + now + '.zip'
else:
target = today + os.sep + now + '_' +
comment.replace(' ', '_') + '.zip'
# Notice the backslash!
# Create the subdirectory if it isn't already there
if not os.path.exists(today):
os.mkdir(today) # make directory
print 'Successfully created directory', today
# 5. We use the zip command (in Unix/Linux) to put the files in a zip archive
zip_command = "zip -qr '%s' %s" % (target, ' '.join(source))
# Run the backup
if os.system(zip_command) == 0:
print 'Successful backup to', target
else:
print 'Backup FAILED'
(源文件:code/backup_ver4.py)
输出
$ python backup_ver4.py
Enter a comment --> added new examples
Successful backup to /mnt/e/backup/20041208/082156_added_new_examples.zip
$ python backup_ver4.py
Enter a comment -->
Successful backup to /mnt/e/backup/20041208/082316.zip
它如何工作
这个程序现在工作了!让我们看一下版本三中作出的实质性改进。我们使用raw_input函数得到
用户的注释,然后通过len函数找出输入的长度以检验用户是否确实输入了什么东西。如果用
户只是按了回车(比如这只是一个惯例备份,没有做什么特别的修改),那么我们就如之前那
样继续操作。
然而,如果提供了注释,那么它会被附加到zip归档名,就在.zip扩展名之前。注意我们把注释
中的空格替换成下划线——这是因为处理这样的文件名要容易得多。
进一步优化
对于大多数用户来说,第四个版本是一个满意的工作脚本了,但是它仍然有进一步改进的空
间。比如,你可以在程序中包含 交互 程度——你可以用-v选项来使你的程序更具交互性。
另一个可能的改进是使文件和目录能够通过命令行直接传递给脚本。我们可以通过sys.argv列表
来获取它们,然后我们可以使用list类提供的extend方法把它们加到source列表中去。
我还希望有的一个优化是使用tar命令替代zip命令。这样做的一个优势是在你结合使用tar和gzip
命令的时候,备份会更快更小。如果你想要在Windows中使用这些归档,WinZip也能方便地处
理这些.tar.gz文件。tar命令在大多数Linux/Unix系统中都是默认可用的。Windows用户也可以下
载安装它。
命令字符串现在将称为:
tar = 'tar -cvzf %s %s -X /home/swaroop/excludes.txt' % (target, ' '.join(srcdir))
选项解释如下:
● -c表示创建一个归档。
● -v表示交互,即命令更具交互性。
● -z表示使用gzip滤波器。
● -f表示强迫创建归档,即如果已经有一个同名文件,它会被替换。
● -X表示含在指定文件名列表中的文件会被排除在备份之外。例如,你可以在文件中指定
*~,从而不让备份包括所有以~结尾的文件。
重要
最理想的创建这些归档的方法是分别使用zipfile和tarfile。它们是Python标准库的一部分,可以
供你使用。使用这些库就避免了使用os.system这个不推荐使用的函数,它容易引发严重的错
误。
然而,我在本节中使用os.system的方法来创建备份,这纯粹是为了教学的需要。这样的话,例
子就可以简单到让每个人都能够理解,同时也已经足够用了。
上一页 上一级 下一页
问题 首页 软件开发过程
75. 简明 Python 教程
第11章 面向对象的编程
上一页 对象的方法 下一页
对象的方法
我们已经讨论了类/对象可以拥有像函数一样的方法,这些方法与函数的区别只是一个额外的
self变量。现在我们来学习一个例子。
使用对象的方法
例11.2 使用对象的方法
#!/usr/bin/python
# Filename: method.py
class Person:
def sayHi(self):
print 'Hello, how are you?'
p = Person()
p.sayHi()
# This short example can also be written as Person().sayHi()
(源文件:code/method.py)
输出
$ python method.py
Hello, how are you?
它如何工作
这里我们看到了self的用法。注意sayHi方法没有任何参数,但仍然在函数定义时有self。
上一页 上一级 下一页
类 首页 __init__方法
76. 简明 Python 教程
第11章 面向对象的编程
上一页 __init__方法 下一页
__init__方法
在Python的类中有很多方法的名字有特殊的重要意义。现在我们将学习__init__方法的意义。
__init__方法在类的一个对象被建立时,马上运行。这个方法可以用来对你的对象做一些你希
望的 初始化 。注意,这个名称的开始和结尾都是双下划线。
使用__init__方法
例11.3 使用__init__方法
#!/usr/bin/python
# Filename: class_init.py
class Person:
def __init__(self, name):
self.name = name
def sayHi(self):
print 'Hello, my name is', self.name
p = Person('Swaroop')
p.sayHi()
# This short example can also be written as Person('Swaroop').sayHi()
(源文件:code/class_init.py)
输出
$ python class_init.py
Hello, my name is Swaroop
它如何工作
这里,我们把__init__方法定义为取一个参数name(以及普通的参数self)。在这个__init__里,
我们只是创建一个新的域,也称为name。注意它们是两个不同的变量,尽管它们有相同的名
字。点号使我们能够区分它们。
最重要的是,我们没有专门调用__init__方法,只是在创建一个类的新实例的时候,把参数包
括在圆括号内跟在类名后面,从而传递给__init__方法。这是这种方法的重要之处。
现在,我们能够在我们的方法中使用self.name域。这在sayHi方法中得到了验证。
给C++/Java/C#程序员的注释
__init__方法类似于C++、C#和Java中的 constructor 。
上一页 上一级 下一页
对象的方法 首页 类与对象的变量
77. 简明 Python 教程
第11章 面向对象的编程
上一页 类与对象的方法 下一页
类与对象的方法
我们已经讨论了类与对象的功能部分,现在我们来看一下它的数据部分。事实上,它们只是与
类和对象的名称空间 绑定 的普通变量,即这些名称只在这些类与对象的前提下有效。
有两种类型的 域 ——类的变量和对象的变量,它们根据是类还是对象 拥有 这个变量而区分。
类的变量 由一个类的所有对象(实例)共享使用。只有一个类变量的拷贝,所以当某个对象
对类的变量做了改动的时候,这个改动会反映到所有其他的实例上。
对象的变量 由类的每个对象/实例拥有。因此每个对象有自己对这个域的一份拷贝,即它们不
是共享的,在同一个类的不同实例中,虽然对象的变量有相同的名称,但是是互不相关的。通
过一个例子会使这个易于理解。
使用类与对象的变量
例11.4 使用类与对象的变量
#!/usr/bin/python
# Filename: objvar.py
class Person:
'''Represents a person.'''
population = 0
def __init__(self, name):
'''Initializes the person's data.'''
self.name = name
print '(Initializing %s)' % self.name
# When this person is created, he/she
# adds to the population
Person.population += 1
def __del__(self):
'''I am dying.'''
print '%s says bye.' % self.name
Person.population -= 1
if Person.population == 0:
print 'I am the last one.'
else:
print 'There are still %d people left.' % Person.population
def sayHi(self):
'''Greeting by the person.
Really, that's all it does.'''
print 'Hi, my name is %s.' % self.name
def howMany(self):
'''Prints the current population.'''
if Person.population == 1:
print 'I am the only person here.'
else:
print 'We have %d persons here.' % Person.population
swaroop = Person('Swaroop')
swaroop.sayHi()
swaroop.howMany()
kalam = Person('Abdul Kalam')
kalam.sayHi()
kalam.howMany()
swaroop.sayHi()
swaroop.howMany()
(源文件:code/objvar.py)
输出
$ python objvar.py
(Initializing Swaroop)
Hi, my name is Swaroop.
I am the only person here.
(Initializing Abdul Kalam)
Hi, my name is Abdul Kalam.
We have 2 persons here.
Hi, my name is Swaroop.
We have 2 persons here.
Abdul Kalam says bye.
There are still 1 people left.
Swaroop says bye.
I am the last one.
它如何工作
这是一个很长的例子,但是它有助于说明类与对象的变量的本质。这里,population属于Person
类,因此是一个类的变量。name变量属于对象(它使用self赋值)因此是对象的变量。
观察可以发现__init__方法用一个名字来初始化Person实例。在这个方法中,我们让population
增加1,这是因为我们增加了一个人。同样可以发现,self.name的值根据每个对象指定,这表
明了它作为对象的变量的本质。
记住,你只能使用self变量来参考同一个对象的变量和方法。这被称为 属性参考 。
在这个程序中,我们还看到docstring对于类和方法同样有用。我们可以在运行时使用Person.
__doc__和Person.sayHi.__doc__来分别访问类与方法的文档字符串。
就如同__init__方法一样,还有一个特殊的方法__del__,它在对象消逝的时候被调用。对象消
逝即对象不再被使用,它所占用的内存将返回给系统作它用。在这个方法里面,我们只是简单
地把Person.population减1。
当对象不再被使用时,__del__方法运行,但是很难保证这个方法究竟在 什么时候 运行。如果
你想要指明它的运行,你就得使用del语句,就如同我们在以前的例子中使用的那样。
给C++/Java/C#程序员的注释
Python中所有的类成员(包括数据成员)都是 公共的 ,所有的方法都是 有效的 。
只有一个例外:如果你使用的数据成员名称以 双下划线前缀 比如__privatevar,Python的名称
管理体系会有效地把它作为私有变量。
这样就有一个惯例,如果某个变量只想在类或对象中使用,就应该以单下划线前缀。而其他的
名称都将作为公共的,可以被其他类/对象使用。记住这只是一个惯例,并不是Python所要求
的(与双下划线前缀不同)。
同样,注意__del__方法与 destructor 的概念类似。
上一页 上一级 下一页
__init__方法 首页 继承
78. 简明 Python 教程
第11章 面向对象的编程
上一页 继承 下一页
继承
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过 继承 机
制。继承完全可以理解成类之间的 类型和子类型 关系。
假设你想要写一个程序来记录学校之中的教师和学生情况。他们有一些共同属性,比如姓名、
年龄和地址。他们也有专有的属性,比如教师的薪水、课程和假期,学生的成绩和学费。
你可以为教师和学生建立两个独立的类来处理它们,但是这样做的话,如果要增加一个新的共
有属性,就意味着要在这两个独立的类中都增加这个属性。这很快就会显得不实用。
一个比较好的方法是创建一个共同的类称为SchoolMember然后让教师和学生的类 继承 这个共
同的类。即它们都是这个类型(类)的子类型,然后我们再为这些子类型添加专有的属性。
使用这种方法有很多优点。如果我们增加/改变了SchoolMember中的任何功能,它会自动地反
映到子类型之中。例如,你要为教师和学生都增加一个新的身份证域,那么你只需简单地把它
加到SchoolMember类中。然而,在一个子类型之中做的改动不会影响到别的子类型。另外一个
优点是你可以把教师和学生对象都作为SchoolMember对象来使用,这在某些场合特别有用,比
如统计学校成员的人数。一个子类型在任何需要父类型的场合可以被替换成父类型,即对象可
以被视作是父类的实例,这种现象被称为多态现象。
另外,我们会发现在 重用 父类的代码的时候,我们无需在不同的类中重复它。而如果我们使
用独立的类的话,我们就不得不这么做了。
在上述的场合中,SchoolMember类被称为 基本类 或 超类 。而Teacher和Student类被称为 导出
类 或 子类 。
现在,我们将学习一个例子程序。
使用继承
例11.5 使用继承
#!/usr/bin/python
# Filename: inherit.py
class SchoolMember:
'''Represents any school member.'''
def __init__(self, name, age):
self.name = name
self.age = age
print '(Initialized SchoolMember: %s)' % self.name
def tell(self):
'''Tell my details.'''
print 'Name:"%s" Age:"%s"' % (self.name, self.age),
class Teacher(SchoolMember):
'''Represents a teacher.'''
def __init__(self, name, age, salary):
SchoolMember.__init__(self, name, age)
self.salary = salary
print '(Initialized Teacher: %s)' % self.name
def tell(self):
SchoolMember.tell(self)
print 'Salary: "%d"' % self.salary
class Student(SchoolMember):
'''Represents a student.'''
def __init__(self, name, age, marks):
SchoolMember.__init__(self, name, age)
self.marks = marks
print '(Initialized Student: %s)' % self.name
def tell(self):
SchoolMember.tell(self)
print 'Marks: "%d"' % self.marks
t = Teacher('Mrs. Shrividya', 40, 30000)
s = Student('Swaroop', 22, 75)
print # prints a blank line
members = [t, s]
for member in members:
member.tell() # works for both Teachers and Students
(源文件:code/inherit.py)
输出
$ python inherit.py
(Initialized SchoolMember: Mrs. Shrividya)
(Initialized Teacher: Mrs. Shrividya)
(Initialized SchoolMember: Swaroop)
(Initialized Student: Swaroop)
Name:"Mrs. Shrividya" Age:"40" Salary: "30000"
Name:"Swaroop" Age:"22" Marks: "75"
它如何工作
为了使用继承,我们把基本类的名称作为一个元组跟在定义类时的类名称之后。然后,我们注
意到基本类的__init__方法专门使用self变量调用,这样我们就可以初始化对象的基本类部分。
这一点十分重要——Python不会自动调用基本类的constructor,你得亲自专门调用它。
我们还观察到我们在方法调用之前加上类名称前缀,然后把self变量及其他参数传递给它。
注意,在我们使用SchoolMember类的tell方法的时候,我们把Teacher和Student的实例仅仅作为
SchoolMember的实例。
另外,在这个例子中,我们调用了子类型的tell方法,而不是SchoolMember类的tell方法。可以
这样来理解,Python总是首先查找对应类型的方法,在这个例子中就是如此。如果它不能在导
出类中找到对应的方法,它才开始到基本类中逐个查找。基本类是在类定义的时候,在元组之
中指明的。
一个术语的注释——如果在继承元组中列了一个以上的类,那么它就被称作 多重继承 。
上一页 上一级 下一页
类与对象的变量 首页 概括
80. 简明 Python 教程
第12章 输入/输出
上一页 文件 下一页
第12章 输入/输出
目录表
文件
使用文件
储存器
储存与取储存
概括
在很多时候,你会想要让你的程序与用户(可能是你自己)交互。你会从用户那里得到输入,
然后打印一些结果。我们可以分别使用raw_input和print语句来完成这些功能。对于输出,你也
可以使用多种多样的str(字符串)类。例如,你能够使用rjust方法来得到一个按一定宽度右对
齐的字符串。利用help(str)获得更多详情。
另一个常用的输入/输出类型是处理文件。创建、读和写文件的能力是许多程序所必需的,我
们将会在这章探索如何实现这些功能。
文件
你可以通过创建一个file类的对象来打开一个文件,分别使用file类的read、readline或write方法来
恰当地读写文件。对文件的读写能力依赖于你在打开文件时指定的模式。最后,当你完成对文
件的操作的时候,你调用close方法来告诉Python我们完成了对文件的使用。
使用文件
例12.1 使用文件
#!/usr/bin/python
# Filename: using_file.py
poem = '''
Programming is fun
When the work is done
if you wanna make your work also fun:
use Python!
'''
f = file('poem.txt', 'w') # open for 'w'riting
f.write(poem) # write text to file
f.close() # close the file
f = file('poem.txt')
# if no mode is specified, 'r'ead mode is assumed by default
while True:
line = f.readline()
if len(line) == 0: # Zero length indicates EOF
break
print line,
# Notice comma to avoid automatic newline added by Python
f.close() # close the file
(源文件:code/using_file.py)
输出
$ python using_file.py
Programming is fun
When the work is done
if you wanna make your work also fun:
use Python!
它如何工作
首先,我们通过指明我们希望打开的文件和模式来创建一个file类的实例。模式可以为读模式
('r')、写模式('w')或追加模式('a')。事实上还有多得多的模式可以使用,你可以使用
help(file)来了解它们的详情。
我们首先用写模式打开文件,然后使用file类的write方法来写文件,最后我们用close关闭这个文
件。
接下来,我们再一次打开同一个文件来读文件。如果我们没有指定模式,读模式会作为默认的
模式。在一个循环中,我们使用readline方法读文件的每一行。这个方法返回包括行末换行符
的一个完整行。所以,当一个 空的 字符串被返回的时候,即表示文件末已经到达了,于是我
们停止循环。
注意,因为从文件读到的内容已经以换行符结尾,所以我们在print语句上使用逗号来消除自动
换行。最后,我们用close关闭这个文件。
现在,来看一下poem.txt文件的内容来验证程序确实工作正常了。
上一页 上一级 下一页
概括 首页 储存器
81. 简明 Python 教程
第12章 输入/输出
上一页 储存器 下一页
储存器
Python提供一个标准的模块,称为pickle。使用它你可以在一个文件中储存任何Python对象,之
后你又可以把它完整无缺地取出来。这被称为 持久地 储存对象。
还有另一个模块称为cPickle,它的功能和pickle模块完全相同,只不过它是用C语言编写的,因
此要快得多(比pickle快1000倍)。你可以使用它们中的任一个,而我们在这里将使用cPickle模
块。记住,我们把这两个模块都简称为pickle模块。
储存与取储存
例12.2 储存与取储存
#!/usr/bin/python
# Filename: pickling.py
import cPickle as p
#import pickle as p
shoplistfile = 'shoplist.data'
# the name of the file where we will store the object
shoplist = ['apple', 'mango', 'carrot']
# Write to the file
f = file(shoplistfile, 'w')
p.dump(shoplist, f) # dump the object to a file
f.close()
del shoplist # remove the shoplist
# Read back from the storage
f = file(shoplistfile)
storedlist = p.load(f)
print storedlist
(源文件:code/pickling.py)
输出
$ python pickling.py
['apple', 'mango', 'carrot']
它如何工作
首先,请注意我们使用了import..as语法。这是一种便利方法,以便于我们可以使用更短的模块
名称。在这个例子中,它还让我们能够通过简单地改变一行就切换到另一个模块(cPickle或者
pickle)!在程序的其余部分的时候,我们简单地把这个模块称为p。
为了在文件里储存一个对象,首先以写模式打开一个file对象,然后调用储存器模块的dump函
数,把对象储存到打开的文件中。这个过程称为 储存 。
接下来,我们使用pickle模块的load函数的返回来取回对象。这个过程称为 取储存 。
上一页 上一级 下一页
文件 首页 概括
84. 简明 Python 教程
第13章 异常
上一页 try..except 下一页
try..except
我们尝试读取用户的一段输入。按Ctrl-d,看一下会发生什么。
>>> s = raw_input('Enter something --> ')
Enter something --> Traceback (most recent call last):
File "<stdin>", line 1, in ?
EOFError
Python引发了一个称为EOFError的错误,这个错误基本上意味着它发现一个不期望的 文件尾
(由Ctrl-d表示)
接下来,我们将学习如何处理这样的错误。
处理异常
我们可以使用try..except语句来处理异常。我们把通常的语句放在try-块中,而把我们的错误处
理语句放在except-块中。
例13.1 处理异常
#!/usr/bin/python
# Filename: try_except.py
import sys
try:
s = raw_input('Enter something --> ')
except EOFError:
print 'nWhy did you do an EOF on me?'
sys.exit() # exit the program
except:
print 'nSome error/exception occurred.'
# here, we are not exiting the program
print 'Done'
(源文件:code/try_except.py)
输出
$ python try_except.py
Enter something -->
Why did you do an EOF on me?
$ python try_except.py
Enter something --> Python is exceptional!
Done
它如何工作
我们把所有可能引发错误的语句放在try块中,然后在except从句/块中处理所有的错误和异常。
except从句可以专门处理单一的错误或异常,或者一组包括在圆括号内的错误/异常。如果没有
给出错误或异常的名称,它会处理 所有的 错误和异常。对于每个try从句,至少都有一个相关
联的except从句。
如果某个错误或异常没有被处理,默认的Python处理器就会被调用。它会终止程序的运行,并
且打印一个消息,我们已经看到了这样的处理。
你还可以让try..catch块关联上一个else从句。当没有异常发生的时候,else从句将被执行。
我们还可以得到异常对象,从而获取更多有个这个异常的信息。这会在下一个例子中说明。
上一页 上一级 下一页
错误 首页 引发异常
85. 简明 Python 教程
第13章 异常
上一页 引发异常 下一页
引发异常
你可以使用raise语句 引发 异常。你还得指明错误/异常的名称和伴随异常 触发的 异常对象。你
可以引发的错误或异常应该分别是一个Error或Exception类的直接或间接导出类。
如何引发异常
例13.2 如何引发异常
#!/usr/bin/python
# Filename: raising.py
class ShortInputException(Exception):
'''A user-defined exception class.'''
def __init__(self, length, atleast):
Exception.__init__(self)
self.length = length
self.atleast = atleast
try:
s = raw_input('Enter something --> ')
if len(s) < 3:
raise ShortInputException(len(s), 3)
# Other work can continue as usual here
except EOFError:
print 'nWhy did you do an EOF on me?'
except ShortInputException, x:
print 'ShortInputException: The input was of length %d,
was expecting at least %d' % (x.length, x.atleast)
else:
print 'No exception was raised.'
源文件(code/raising.py)
输出
$ python raising.py
Enter something -->
Why did you do an EOF on me?
$ python raising.py
Enter something --> ab
ShortInputException: The input was of length 2, was expecting at least 3
$ python raising.py
Enter something --> abc
No exception was raised.
它如何工作
这里,我们创建了我们自己的异常类型,其实我们可以使用任何预定义的异常/错误。这个新
的异常类型是ShortInputException类。它有两个域——length是给定输入的长度,atleast则是程序
期望的最小长度。
在except从句中,我们提供了错误类和用来表示错误/异常对象的变量。这与函数调用中的形参
和实参概念类似。在这个特别的except从句中,我们使用异常对象的length和atleast域来为用户
打印一个恰当的消息。
上一页 上一级 下一页
try..except 首页 try..finally
86. 简明 Python 教程
第13章 异常
上一页 try..finally 下一页
try..finally
假如你在读一个文件的时候,希望在无论异常发生与否的情况下都关闭文件,该怎么做呢?这
可以使用finally块来完成。注意,在一个try块下,你可以同时使用except从句和finally块。如果
你要同时使用它们的话,需要把一个嵌入另外一个。
使用finally
例13.3 使用finally
#!/usr/bin/python
# Filename: finally.py
import time
try:
f = file('poem.txt')
while True: # our usual file-reading idiom
line = f.readline()
if len(line) == 0:
break
time.sleep(2)
print line,
finally:
f.close()
print 'Cleaning up...closed the file'
(源文件:code/finally.py)
输出
$ python finally.py
Programming is fun
When the work is done
Cleaning up...closed the file
Traceback (most recent call last):
File "finally.py", line 12, in ?
time.sleep(2)
KeyboardInterrupt
它如何工作
我们进行通常的读文件工作,但是我有意在每打印一行之前用time.sleep方法暂停2秒钟。这样
做的原因是让程序运行得慢一些(Python由于其本质通常运行得很快)。在程序运行的时候,
按Ctrl-c中断/取消程序。
我们可以观察到KeyboardInterrupt异常被触发,程序退出。但是在程序退出之前,finally从句仍
然被执行,把文件关闭
上一页 上一级 下一页
引发异常 首页 概括
89. 简明 Python 教程
第14章 Python标准库
上一页 sys模块 下一页
sys模块
sys模块包含系统对应的功能。我们已经学习了sys.argv列表,它包含命令行参数。
命令行参数
例14.1 使用sys.argv
#!/usr/bin/python
# Filename: cat.py
import sys
def readfile(filename):
'''Print a file to the standard output.'''
f = file(filename)
while True:
line = f.readline()
if len(line) == 0:
break
print line, # notice comma
f.close()
# Script starts from here
if len(sys.argv) < 2:
print 'No action specified.'
sys.exit()
if sys.argv[1].startswith('--'):
option = sys.argv[1][2:]
# fetch sys.argv[1] but without the first two characters
if option == 'version':
print 'Version 1.2'
elif option == 'help':
print '''
This program prints files to the standard output.
Any number of files can be specified.
Options include:
--version : Prints the version number
--help : Display this help'''
else:
print 'Unknown option.'
sys.exit()
else:
for filename in sys.argv[1:]:
readfile(filename)
(源文件:code/cat.py)
输出
$ python cat.py
No action specified.
$ python cat.py --help
This program prints files to the standard output.
Any number of files can be specified.
Options include:
--version : Prints the version number
--help : Display this help
$ python cat.py --version
Version 1.2
$ python cat.py --nonsense
Unknown option.
$ python cat.py poem.txt
Programming is fun
When the work is done
if you wanna make your work also fun:
use Python!
它如何工作
这个程序用来模范Linux/Unix用户熟悉的cat命令。你只需要指明某些文本文件的名字,这个程
序会把它们打印输出。
在Python程序运行的时候,即不是在交互模式下,在sys.argv列表中总是至少有一个项目。它就
是当前运行的程序名称,作为sys.argv[0](由于Python从0开始计数)。其他的命令行参数在这
个项目之后。
为了使这个程序对用户更加友好,我们提供了一些用户可以指定的选项来了解更多程序的内
容。我们使用第一个参数来检验我们的程序是否被指定了选项。如果使用了--version选项,程
序的版本号将被打印出来。类似地,如果指定了--help选项,我们提供一些关于程序的解释。
我们使用sys.exit函数退出正在运行的程序。和以往一样,你可以看一下help(sys.exit)来了解更多
详情。
如果没有指定任何选项,而是为程序提供文件名的话,它就简单地打印出每个文件地每一行,
按照命令行中的顺序一个文件接着一个文件地打印。
顺便说一下,名称cat是 concatenate 的缩写,它基本上表明了程序的功能——它可以在输出打
印一个文件或者把两个或两个以上文件连接/级连在一起打印。
更多sys的内容
sys.version字符串给你提供安装的Python的版本信息。sys.version_info元组则提供一个更简单的
方法来使你的程序具备Python版本要求功能。
[swaroop@localhost code]$ python
>>> import sys
>>> sys.version
'2.3.4 (#1, Oct 26 2004, 16:42:40) n[GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)]'
>>> sys.version_info
(2, 3, 4, 'final', 0)
对于有经验的程序员,sys模块中其他令人感兴趣的项目有sys.stdin、sys.stdout和sys.stderr它们分
别对应你的程序的标准输入、标准输出和标准错误流。
上一页 上一级 下一页
简介 首页 os模块