之前为了编写一个svm分词的程序而简单学了下Python。认为Python非常好用。想深入并系统学习一下,了解一些机制,因此開始阅读《Python学习手冊(第三版)》。
假设仅仅是想高速入门。我在这里推荐了几篇文章,有其它语言编程经验的人简单看一看就能够非常快地開始编写Python程序了。
黑体表示章节。 下划线表示能够直接在原文相应位置查到的专有技术名词。
原书配套答案请到http://www.hzbook.com/Books/4572.html下载,简单注冊就可以。
第三章 怎样执行程序
import进行模块导入仅仅能执行一次。多次执行需使用reload。
模块往往是变量名的封装,被觉得是命名空间。比如:
#myfile.py
title = "test" >>>import myfile
>>>print myfile.title
test
替代方案是from,以下有相同的效果:
>>>from myfile import title
>>>print tittle
test
from myfile import * 则能够把myfile所有变量所有导入(第19章内容)。
第四章 介绍Python对象类型
尽管字符串支持多种操作。可是它具有不可变性,即原字符串不能改变,仅仅能用新字符串作为结果赋予一个变量。
以下是一个试图改变原字符串的操作及报错信息:
>>> s="spam"
>>> s[0] = 'z'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
第五章 数字
str和repr显示格式
>>>num = 1/3.0
>>>num
0.33333333333333331
>>>print num
333333333333 >>>repr(num)
'0.33333333333333331' #交互模式回显
>>>str(num)
'333333333333' #打印语句
浮点数运算在精确方面有缺陷。
这和硬件有关,打印结果也不能全然解决。
>>> 0.1+0.1+0.1-0.3
5.551115123125783e-17
>>> print 0.1+0.1+0.1-0.3
5.55111512313e-17
使用小数对象能够进行修正
>>> from decimal import Decimal
>>> Decimal('0.1') + Decimal('0.1') + Decimal('0.1') - Decimal('0.3')
Decimal('0.0')
第六章 动态类型简单介绍
a = 3这个语句实际上运行了三个步骤:创建一个对象代表值3。假设还未创建,创建一个变量a;将变量与新的对象3连接。这时,变量a成为了对象3的一个引用。也能够看做是指针。
类型属于对象,而不是变量,这就非常好理解为什么Python中同一个变量名能够作为不同类型的对象的引用了。
在这样的机制下。每一个对象都有一个引用计数器。当计数器为0时就被系统回收。这便是Python中对象的垃圾收集的方法了。
不同变量引用同一个数字或字符串时,对变量操作(eg.a=3 a=a+2)仅仅是创建了一个新的对象并使它引用新对象,这也是上一章提到的字符串不能修改的原因。而对于一些类型来说,有的操作确实能改变对象,例如以下所看到的:
#situation 1
>>>L1=[2,3,4]
>>>L2=L1
>>>L1=24
>>>L2
[2,3,4] #situation 2
>>L1=[2,3,4]
>>>L2=L1
>>>L2[0]=24
>>>L1
[24,3,4]
为了让两个变量使用不同的对象。能够拷贝对象,使用L2=L1[:]来取代L2=L1就可以。对于字典则使用D.copy()方法。标准库的copy模块提供了一个对随意对象的调用方法。以下两种方式的差别暂不讨论:
import copy
X = copy.copy(Y) #表层拷贝
X = copy.deepcopy(Y) #深拷贝
这里就出现了个问题。两个引用是否是同一对象?能够用以下的方式推断:
>>>L=[1,2,3]
>>>M=L
>>>L== M
True
>>>L is M
True
负值索引相当于从末尾倒数。-1就是最后一个元素的索引。
对于s="spam",-5是个非法的索引值。分号:前的空值表示从第一个開始,后的空值表示直到最后一个。
第七章 字符串
单双引號是一样的。这样同意用户不使用转移字符来实现带有单或双引號的字符串。个人觉得避免了按shift才干使用双引號“的麻烦。
>>>'knight"s ',"knight's"
('knight"s ',"knight's")
此外,合并相邻的字符串常量。如'knight"s ' "knight's"(中间有空格)会显示为'knight"s knight\'s'。可见。最外层是单引號,为了保持原内容。Python把单引號里的单引號改写成了转义字符,这个样例和书上的不同,更有助于理解。转义字符和C非常类似,多了几种。可是Python里没有空字符串,Python为每一个字符串保存了内容和长度。
同一时候,假设一个字符串中没有合法的转义编码出如今"\"后,那么它将在字符串中保留反斜线。抑制转义的方法是在字符串前加r,如r"C:\new\text.dat"。此时的\n和\t就不会被当做是转义字符,同一时候。这样做也不必把\改写成\\。
三重引號适用于多行的字符串的直接输入而不使用转义字符。利用三重引號也能够实现类似C中/* */凝视掉代码的目的。
Unicode字符串通过在前面加u获得。
扩展分片是第三个索引。用作步进。
这时完整的分片形式为X[I:J:K]。当中步进为K。
当步进取-1时,能够把字符串反转,非常奇妙的方法。
利用分片,能够对字符串进行改动。即把新字符串加到原字符串上,再把原字符串切掉。
字符串格式化的使用方法与C的printf非常像。不同之处在于全部參数外须要加一个(),形成%(arg1,arg2,arg3)的形式。
格式化代码请參考原书表格,通用结构:%[(name)][flags][width][.precision]code。当中name能够是字典名。这时在參数表里提供这个字典的键就可以。
既然字符串是对象,那么它就有相应的方法。书上介绍了改动字符串的replace()、查找find()、把每一个元素取出创建列表的list()、把列表合并成字符串的join()(能够作为list()的反操作)、提取组件的split()。
第八章 列表
用中括号表示列表,列表的组成对象是有序的。组成列表的各个对象同意不同。
用大括号表示字典,字典的组成对象是无序的,字典键的搜索方式是哈希搜索,速度非常快。
能够用字典来模拟列表:使用序数作为字典的索引就可以。
类似地,字典能够用来表示一些稀疏矩阵。
字典的get方法用于避免不存在的键,假设键不存在。返回值是0。
字典接口是使用方式类似字典而且实际工作都和字典一样的一些Python扩展程序的接口。
第9章 元组、文件及其它
用小括号表示元组,元组不能原处改动。
为了避免仅仅含一个元素的元组被当做表达式。使用一个逗号,写为(40,)。逗号能够帮助识别元组,以下的也是元组的表示方式:
t = 0,'Ni',1.2,3
从文件里读取的是字符串,须要作为其它类型来操作时必须转换。
eval()用来把字符串作为对象。因此也能够达到运行Python的不论什么表达式。
pickle模块能够直接在文件里存储差点儿不论什么Python对象。
struct模块提供了二进制数据的打包。打包+存入文件。读取文件+解包。
在“赋值VS引用”这一节,对于复合方式的赋值,改动其成员会导致全部使用该成员的对象的改变。直观来看就是以下:
>>>X = [1,2,3]
>>>L = ['a', X, 'b']
>>>D = {'x':X, 'y':2}
>>>X[1] = 'surprise'
>>>L
['a', [1,'surprise',3], 'b']
>>>D
{'x':[1,'surprise',3], 'y':2}
这是一个陷阱,为了避免这样的情况。依据详细类型使用拷贝(比方分片、copy方法)而不是引用。
Python内部临时存储并反复使用短字符串。因此对相同内容的字符串,is判定可能依据其长度为True(字符串较短时)或False(字符串较长时)。
不同类型的比較(用==进行)的判定方式不一样。
还有其它内置类型陷阱,如反复能添加层次深度。循环数据结构L=L.append(L)
第二部分练习题
2.(摘自附录B)分片运算超出边界(比如,L[-1000:100])可工作,由于Python会缩放超出边界的分片(必要时,限制值可设为零和序列长度)。以翻转的方式提取序列是行不通的(较低边界值比較高边界值更大,比如,L[3:1])。你会得到空分片([ ]),由于Python会缩放分片限制值,以确定较低边界永远比較高边界小或相等(比如,L[3:1]会缩放成L[3:3],空的插入点是在偏移值3处)。
Python分片一定是从左至右抽取。即使你用负号索引值也是这样(会先加上序列长度转换成正值)。
注意到,Python
2.3的第三限制值分片会略微改动此行为:L[3:1:-1]的确是从右至左抽取。
3.索引运算、分片运算以及del:对于L=[1,2,3,4], L[2] = []仅仅能把3变为[],而L[2:3] = []却能删掉第三项。
4.X,Y = Y,X,左边视为两个对象,右边视为一个元组,这个表达式交换了两个引用。
第10章 Python语句简单介绍
绝大多数的Python程序每行一个语句,不须要分号。Python的风格就是全然不要分号,尽管在语句末加上分号也能通过。
唯一须要分号的情况是一行中多个语句的分隔符。
相反地,括号能够使一个语句分隔成非常多行。比方用列表直观地定义一个矩阵时。反斜线\也能够达到这个目的。
嵌套代码仅仅须要保持缩进一致就可以。Python是WYSIWYG语言(what you see is what you get,所见即所得)
第11章 赋值、表达式和打印
形如X+=Y的赋值语句称为增强赋值语句,它有三个长处:程序猿输入降低,左側仅仅须要计算一次(X=X+Y中X计算两次),优化技术会自己主动选择(支持原处改动的类型能够直接原处改动)。
单一下划线开头的变量名不会被from module import *这种语句导入。前后都有双下划线的变量名是系统定义的变量名,对解释器有特殊意义。双下划线开头但结尾没有双下划线的变量是类的本地变量(參考第19章)。
表达式语句通经常使用于运行可原处改动列表的列表方法。即对于列表L,L.append(3)是正确的,而L=L.append(4)是错误的,第二个式子右边返回的是None。
标准输出的重定向方法:
import sys
sys.stdout = open('log.txt','a')
...
print x,y,x #写入log.txt
为了避免忘记恢复sys.stdout,写入log.txt也能够用:
log = open('log.txt','a')
print >>log, x, y, x
第12章 if測试
类似于C。Python的布尔运算or是短路运算,而它返回第一个为真的操作对象。或者是第二个为假的对象。[ ] or { } 将返回{ }。
if选择分支有下面几种等价形式:
#最常见的分支形式
if X:
A = Y
else:
A = Z #Python2.5以后引入
A = Y if X else Z #Python2.5曾经(以后也兼容)
#须要理解and和or的运算和返回值规则
A = ((X and Y) or Z) #列表形式
A = [Z,Y][bool(X)]
第13章 while和for循环
pass语句是无运算的占位符,为了表示语法须要语句而且还没有不论什么有用的语句可写时就能够使用它。
while和for循环都有一个可选的else语句,在循环条件不满足时且没实用break结束循环时使用。
C语言形式的 while((x = next()) != NULL) { ...process x...}在Python里行不通:C语言赋值语句会返回赋值后的值,而Python赋值语句仅仅是语句,不是表达式。
Python的迭代协议:有next方法的对象会前进到下一个结果。而在末尾时引发StopIteration。
全部的迭代工具内部工作都调用next,并捕捉StopIteration异常来确定何时离开。
用for改动列表时,for x in L:x+=1是无法改动的,由于它改动的是循环变量x而不是列表L。应该使用L[i] +=1的索引来控制改动。
zip()能够用于for并行改动多个对象时的情况(按最短的截断)。
它也能够用来再循环中建立列表:for (k,v) in zip(keys, vals):D[k]=v。
enumerate()用于产生偏移和元素:for (offset,item) in enumerate(S): print offset,item
主要的列表解析:L=[x+10 for x in L]
扩展的列表解析。删除文件里的换行符:
lines = [line.rstrip() for line in open('script1.py') if line[0] =='p']
从文件里逐行读取文本行的最佳方法是不要刻意去读:
for line in open('script1.py'):
print line.upper()
第十四章 文档
__doc__属性封装了对象上的文档,通过它能够查看(比方函数的)凝视。
文档字符串被觉得最是用于较大、功能性的文档,而#最好仅仅限于关于费解的表达式或语句的微型文档。
PyDoc系统可以将前者取出并显示。
第十五章 函数基础
def是可执行代码,直到执行了def时其定义的函数才開始存在。
因为函数的參数没有类型规定。因此能够非常方便地实现多态:
>>>def times(x,y):
... return x*y
... >>>times(2,4)
8
>>>times('Ni',4)
'NiNiNiNi'
第十六章 作用域与參数
变量名解析的LEGB原则:变量名引用分为三个作用域进行查找。本地作用域(L。每次调用函数时创建)、上一级调用的本地作用域(E)、全局作用域(G。模块作用域)、内置作用域(B,提前定义的变量名如open)。
仅对简单变量生效,对于特定对象的变量如object.spam,查找规则规则全然不同。
内置作用域是一个名为__builtin__的内置模块,import后才干够使用,这时能够用dir(__buildin__)查看提前定义的变量名。依据LEGB原则,在本地作用域定义一个新的open = 'spam'会导致open()函数不能被调用。
global用于全局变量声明。
作者觉得在模块导入时,导入其它模块的模块拥有了对其它模块变量的改动权,这使得被导入模块的维护变得复杂:维护者不知道第二个模块什么情况下会改动变量。因此最好的解决的方法是不这样做,在文件间进行通信的最好办法就是通过调用函数。传递參数。然后获得返回值(用函数提供改动变量的接口,而且告诉维护者这个变量能够被其它模块改变)。
工厂函数(又称闭合),是能记住嵌套作用域的变量值的函数。
演示样例:
>>> def maker(N):
... def action(X):
... return X ** N
... return action
...
>>> f = maker(2)
>>> f #显示f的引用
<function action at 0xb7738294>
>>> f(3)
9
>>> f(4)
16
>>> g = maker(3)
>>> g(3)
27
>>> f(3)
9
对于函数參数,不可变參数是通过传值来传递,可变对象(列表、字典等)是通过传引用进行传递的。
多个返回值的经常使用return方式是使用元组。
函数參数的四种匹配方式:位置匹配、keyword參数、全部对象、全部keyword/值:
>>>def f(a,b,c):print a,b,c #常规匹配
>>>f(1,2,3)
1 2 3 >>>f(c=3,b=2,a=1) #keyword匹配
1 2 3 >>>f(1,c=3,b=2) #位置+keyword匹配
1 2 3 >>>def f(a,b=2,c=3):print a,b,c #默认參数
>>>f(1)
1 2 3
>>>f(a=1)
1 2 3 >>>def f(*args):print args # 随意參数*
>>>f()
()
>>>f(1)
(1,)
>>>f(1,2,3,4) >>>def f(**args):print args # 随意參数**,把參数组装成为字典
>>>f()
{}
>>>f(a=1,b=2)
{'a'=1,'b'=2}
相反地,调用函数在參数变量前面加*能够分解參数。
參数匹配顺序:调用和定义中先是非keyword參数(name)、然后是keyword參数(name=value)、*name最后是**name。
第17章 函数的高级话题
def f(x,y,z):return x+y+z和f= lambda x,y,z:x+y+z会达到相同的效果。lambda是一个表达式,而不是语句,同意出如今def不能出现的地方。正是由于这个特点,lambda比def的使用更加灵活,比方编写跳转表(也即行为的列表或字典):L=[(lambda x:x**2),[(lambda x:x**3),[(lambda
x:x**4)]。出于代码易读性的考虑,应尽量避免嵌套的lambda。
apply的介绍略过。它能够用*和**型參数取代。
(似乎在Python3.0以上版本号已废弃,待确认)
map(func,arg)能够非常方便的用函数func处理列表类型的数据,而自己编写类似的功能须要使用for来完毕。
filter和reduce这两个函数工具分别用于列表过滤和列表全元素的逐个运算。
关于列表解析。带if条件的之前已提过,不再反复。for的应用演示样例:
>>> res = [x+y for x in [0,1,2] for y in [100,200,300]]
>>> res
[100, 200, 300, 101, 201, 301, 102, 202, 302]
更进一步的嵌套:
>>>[(x,y) for x in range(5) if x%2 ==0 for y in range(5) if y%2==0]
作者在这里开了个小玩笑:“而map和filter的等效形式往往更复杂也会有深层的嵌套,这里不进行说明。将这部分代码留给禅师、前LISP程序猿以及犯罪神经病作为练习”。
生成器函数与一般函数不同之处在于,它yield而不是return一个值,并把自己挂起,现场保存在下一次调用。为与列表解析相区分,能够使用圆括号作为生成器表达式:
>>> for num in (x **2 for x in range(4)):
... print '%s,%s' %(num,num/2.0)
...
0,0.0
1,0.5
4,2.0
9,4.5
一个測试不同的迭代方法的小程序。当然。对于不同的操作。不同方法的相对速度可能不一样。不存在全部情况下都最快的“最优方法”:
#file timerseqs.py
import time,sys
reps = 1000
size = 10000 def tester(func, *args):
startTime = time.time()
for i in range(reps):
func(*args)
elapsed = time.time() - startTime
return elapsed def forStatement():
res = []
for x in range(size):
res.append(abs(x)) def listComprehension():
res = [abs(x) for x in range(size)] def mapFunction():
res = map(abs, range(size)) def generatorExpression():
res = list(abs(x) for x in range(size)) print sys.version
tests = (forStatement, listComprehension, mapFunction,generatorExpression)
for testfunc in tests:
print testfunc.__name__.ljust(20), '=>',tester(testfunc)
陷阱:本地变量是静态检測的。这意味着假设在模块里定义了X=99,def一个函数print X后又在函数里X=88,那么就会报错。
陷阱:默认对象在def时赋值,而不是调用函数时赋值。
第18章 模块:雄伟蓝图
Python进行import时搜索文件夹的顺序:主文件夹、PYTHONPATH环境变量文件夹、标准库文件夹、.pth文件夹。
第19章 模块代码编写基础
将会被用于导入的模块文件命名须要以.py做结尾。
当两个不同模块使用了同样的变量名时,不能用from。仅仅能用import。
(本章大部分内容都在第三章介绍过)
第20章 模块包
import时列出路径名称,以点号相隔:import dir1.dir2.mod。
这与平台无关,import不能使用平台特定的路径表达方式。同一时候,这也表明文件名称省略了.py的原因。另外,dir1和dir2中必须包括一个__init__.py文件(能够为空,Python首次进入其所在文件夹时会运行它的内容)。每次使用路径必须完整输入。使用import dir1.dir2.mod as mod中定义的mod取代前面过长的路径名能够解决问题。
个人觉得。模块包是为了方便同名模块的使用不发生混淆的方式,这是软件开发时所须要的。
第21章 高级模块话题
_X的命名方式能够防止from *导入这个变量,然而这样的方法不能阻止其它导入方式的导入,并非一些面向对象语言中的私有声明。
__all__会列出from *复制的变量名,与_X正相反。
相同仅仅对from *有效,不是私有声明。
from __feature__ import featurename还不是非常理解,好象是用选用扩展功能的方式开启特殊的代码编译。
模块能够通过检測自己的__name__是否为"__main__"确定它是在运行还是被导入。这样能够让模块在扮演两种不同角色时发挥不同功能。
相对导入:路径以一个点開始,定位同一个包的模块。能够开启__feature__中强迫导入的绝对性。
非常类似于Linux,两个点表示上一级路径。
陷阱一:顶层代码的语句次序。被import时模块的顶层代码会马上运行。此时它所引用后文定义的变量将无效。
陷阱二:字符串变量是不能直接用于import语句的。能够使用exec "import" + modname来使用字符串modname。这样做仍然有个缺点,每次运行时必须编译import语句。更好的取代方案是string = __import__(modname)。然后把string单列一行运行就可以。
陷阱三:from复制变量名而不是拷贝。
#nested1.py
X = 99
def printer():print X #nested2.py
from nested1 import X,printer
X = 88
printer() %python nested2.py
99
陷阱四:reload不影响from导入。为了更新变量,使用.运算符来导入和改动其它模块的变量。
陷阱五:reload、from及交互模式測试。这部分比較有启示性,建议在原书细致阅读。简要概括就还是:导入后(模块)要重载(模块),重载后还要又一次运行import(变量)。
reload和from的合作并不完美,最佳原则是使用reload和import来启动程序。
陷阱六:重载没有传递性。
重载A不会重载A中import的B和C。
须要这样的功能时能够自己编写一个通用工具。
import types
def status(module):
print 'reloading',module.__name__ def transitive_reload(module,visited):
if not visited.has_key(module):
status(module)
reload(module)
visited[module] = None
for attrobj in module.__dict__.values(): #For all attrs
if type(sttrobj) == types.ModuleType:
transitive_reload(attrobj,visited) def reload_all(*args):
visited = {}
for arg in args:
if type(arg) == types.Module Type:
transitive_reload(arg,visited) if __name__ == '__main__':
import reloadall
reload_all(reloadall)
陷阱七:递归导入。
第22章 OOP:雄伟蓝图
属性一般是在class语句中通过赋值语句加入在类中,而不是在定义类时嵌入。因此对没有赋值的对象属性的訪问会出错。
类方法函数第一个參数通常为self(调用时不指明),但不一定叫self,位置是关键(来自习题5)。作为类方法直接调用时,需指明实例的名称(24章)。
Python的OOP模型事实上就是在对象树中搜索属性。
(笔者有部分OOP基础,因此本章详细理论和理解略去)
第23章 类代码编写基础
类事实上也是一种对象。
在类定义外创建的函数也能够成为方法:
>>>def upperName(self):
... return self.name.upper() >>>rec.method = upperName
第24章 类代码编写细节
和def一样,class也是可执行代码,执行时才会产生类对象。
调用超类的构造器是能够的,在子类的构造方法中使用Super.__init__()就可以。
抽象超类有的方法没有提供实现,而是由子类提供。
类的运算符重载通过改动诸如__add__(相应于+)等方法来实现。详细细节请參考原书。以下是一个改动__iter__获得用户定义的迭代器的样例:
class Squares:
def __init__(self,start,stop):
self.value = start - 1
self.stop = stop
def __iter__(self):
return self
def next(self):
if self.value == self.stop:
raise StopIteration
self.value += 1
return self.value ** 2 %python
>>>from iters import Squares
>>>for i in Squares(1,5):
... print i,
...
1 4 9 16 25
__setattr__的改动能够模拟实现成员变量私有性,这里不贴书中的源代码了。
右側方法如__radd__中,self在右側。和__add__相反。
__call__能够拦截调用,用使用函数的方法使用类。对改写了__call__的类prod,实例化x = prod(2),x(3)能够直接使用。
__del__是析构器。但在Python中非常少使用析构方法。
命名空间事实上是普通的字典。
第25章 类的设计
无绑定类方法对象无self必须明白提供实例对象做第一个參数。绑定实例方法对象用self+函数对,不用传递实例。
托付是指把对象包装在代理类中。
#trace.py
class wrapper:
def __init__(self,object):
self.wrapped = object
def __getattr__(self,attrname):
print 'Trace:',attrname
return getattr(self.wrapped,attrname) >>>from trace import wrapper
>>>x = wrapper([1,2,3])
>>>x.append(4)
Trace:append
>>>x.wrapped
[1,2,3,4]
组合是一种技术。让控制器类嵌入和引导一群对象,并自行提供接口。
(这一章主要内容是帮助读者从面向过程向面向对象过渡,并且比較浅显,在这方面作者推荐继续去读设计模式的书效果会更好,这里就不具体介绍了)
第26章 类的高级主题
伪私有属性:将开头两个下划线的变量名前再加上_类名。
仍然不是真正的私有。
新式类从内置类型创建子类,或者直接用object作为超类。3.0以后全部类自己主动成为新式类。钻石继承在新式类里从括号最右開始搜索。这与经典类正相反。
为了解决继承不同类同名变量冲突,能够进行强制规定,如attr = B.attr。
__slots__用来限制类的实例能有的合法属性集。
内容属性使用拦截的方式来提供属性,可是它本身不是成员变量。
类似于改写__getattr__。使用property()进行。
静态方法和类方法分别须要调用staticmethod和classmethod两个函数,前者调用不须要实例(实例调用时)。后者把类传入类方法第一个參数。
函数装饰器在def上一行用@标明,有点像包裹函数,@A @B @C后def f()相当于f=A(B(C(f)))。
第27章 异常基础
try/except能够用于捕捉异常并从异常中恢复。而try/final能够保证不管是否发生异常,终止行为都一定会进行。
二者也能够合并使用(2.5版以后)。else在不发生异常时运行。
except有几种分句形式(请參考原书)。
rasie、assert用于触发异常。raise后不带參数表示又一次引发当前异常(第28章)。
with/as能够用作try/final的替代方案。as后面是with后表达式的赋值对象。
第28章 异常对象
字符串异常(myexc = "My exception string";raise myexc)已经在3.0以后消失,如今经常使用的是基于类的异常。类异常比字符串异常方便之处在于。能够在原始版本号中用超类定义异常。在兴许版本号中使用子类来描写叙述新的异常,这为版本号维护提供了极大的方便。字符串异常的推断方式是is而不是==(常见陷阱,29章)。
第29章 异常的设计
嵌套的try,引发异常时except会回到先前进入但未离开的try,而finally不会停止传递。
用try进行调试的方式,在发生错误时程序仍处于激活状态,能够进行其它的測试而不是又一次開始:
try:
...run program...
except:
import sys
print 'uncaught!', sys.exc_info()[0], sys.exc_info()[1]
#sys.exc_info有专门一小节解说,无异常返回3个None
#反之返回type value tracebck