Python 点滴 V

【异常语句】

try/except:   捕捉由PYTHON自身或写程序过程中引发的异常并恢复

try/finally:  无论异常是否发生,执行清理行为

raise:        手动在代码中触发异常

assert:       有条件地在程序代码中触发异常

with/as       PYTHON后续版本中实现环境管理器

【异常的角色】

下面是它最常见的几种角色

1. 错误处理

>>>可以在程序代码中捕捉和相应错误,或者忽略已发生的异常。

>>>如果忽略错误,PYTHON默认的异常处理行为将启动:停止程序,打印错误信息。

>>>如果不想启动这种默认行为,就用try语句来捕捉异常并从异常中恢复。

2. 事件通知

>>>异常也可用于发出有效状态的信号,而不需在程序间传递结果标志位。或者刻意对其进行测试

3. 特殊情况处理

>>>有时,发生了某种很罕见的情况,很难调整代码区处理。通常会在异常处理中处理,从而省去应对特殊情况的代码

4. 终止行为

>>>try/finally语句可确保一定会进行需要的结束运算,无论程序是否有异常

5. 非常规控制流程

>>>异常是一种高级的goto,它可以作为实现非常规的控制流程的基础。

>>虽然反向跟踪并不是语言本身的一部分,但它能够通过PYTHON异常来实现,需要一些辅助逻辑来退回赋值语句

【新版本自定义类异常例子】

>>> class MyBad(Exception): pass

>>> def doomed(): raise MyBad

>>> try:

...   doomed()

... except MyBad:

...   print ‘got bad‘

...

got bad

【PYTHON整个异常控制流程】

1. 由PYTHON或程序触发的异常,可以忽略(打印错误信息),也可以由try语句进行扑捉。

2. try语句有两种逻辑格式:

一种是处理异常

另一种是执行最终的代码,而不管异常是否发生.

3. PYTHON的raise,assert可以按照需要触发异常

【try语句格式】

【默认行为例子】

def func(x,y):

return x / y

def test(x):

func(x,0)

test(1)

执行结果:

>>>

Traceback (most recent call last):

File "D:\python\test.py", line 7, in <module>

test(1)

File "D:\python\test.py", line 5, in test

func(x,0)

File "D:\python\test.py", line 2, in func

return x / y

ZeroDivisionError: integer division or modulo by zero

PYTHON没有捕捉的异常会向上传递到PYTHON进程的顶层,并执行PYTHON默认异常处理逻辑,也就是说,PYTHON终止执行中的程序,并打印标准错误信息。

【捕捉内置异常】

def func(x,y):

return x + y         #会触发类型异常错误

try:

func([1,2,3],‘abc‘)

except TypeError:        #捕捉并恢复

print ‘Hello,World!‘

print ‘resume here!‘     #程序继续执行

执行结果:

>>>

Hello,World!

resume here!

NOTE:

1. 一旦捕捉到异常,控制权会在捕捉的地方继续下去,没有直接的方式回到异常发生的地方.

2. 如果这里没有捕捉到异常,比如说,执行下面的语句

except ZeroDivisionError:

则后面的程序就会终止而不会执行

【try/finally语句例子】

try:

<statements>       #首先运行可能触发异常的语句

finally:

<statements>       #不管前面是否有异常,finally语句块都会执行

finally语句主要用于:文件关闭,服务器断开等

class MyError(Exception):

pass

def func(file):

raise MyError

f = open(‘data‘)    #打开文件

try:

func(f)         #手动触发异常

finally:

f.close()       #总是会关闭文件

print ‘file closed...‘

【合并try的例子】

下面例子示范了四种常见场景,通过print语句说明其意义

第一种:异常触发并捕获
print '-' * 30,'\nEXCEPTION RAISED AND CAUGHT'

try:
    x = 'spam'[99]
except IndexError:
    print 'except run'
finally:
    print 'finally run'
print 'after run'
第二种:无异常触发
print '-' * 30,'\nNO EXCEPTION RAISED'
try:
    x = 'spam'[3]
except IndexError:
    print 'except run'
finally:
    print 'finally run'
print 'after run'
第三种:无异常触发,ELSE语句执行
print '-' * 30,'\nNO EXCEPTION RAISED, ELSE RUN'
try:
    x = 'spam'[3]
except IndexError:
    print 'except run'
else:
    print 'else run'
finally:
    print 'finally run'
print 'after run'
第四种:异常触发,但没有捕获
print '-' * 30,'\nEXCEPTION RAISED BUT NOT CAUGHT'
try:
    x = 1 / 0
except IndexError:
    print 'except run'
finally:
    print 'finally run'
print 'after run'

执行结果:

>>>
------------------------------
EXCEPTION RAISED AND CAUGHT
except run
finally run
after run
------------------------------
NO EXCEPTION RAISED
finally run
after run
------------------------------
NO EXCEPTION RAISED, ELSE RUN
else run
finally run
after run
------------------------------
EXCEPTION RAISED BUT NOT CAUGHT
finally run

Traceback (most recent call last):
  File "D:\python\test.py", line 34, in <module>
    x = 1 / 0
ZeroDivisionError: integer division or modulo by zero

【raise语句】

要故意触发异常,请使用raise. 形式简单,使用方便.

格式一: raise <name>         #手工触发一个异常

格式二: raise <name>, <data> #触发异常并传递额外的数据到捕获器

格式三: raise                #重新触发,如果想把刚捕获的异常传递给另外一个处理器,必须用到

【raise简单例子】

class MyError:               #定义MyError类,注意字符串不能用于捕获

print ‘My Error class‘

def func():

raise MyError            #手工触发自定义异常类

try:

func()                   #尝试捕获异常

except MyError:              #匹配/查找,触发的异常是否一致

print ‘got myError‘      #如match,则处理异常

【利用raise传递额外的数据】

raise语句可以随异常一起传递额外的数据项给处理器使用。一般而言,额外数据可以向处理器传递关于异常的背景信息。例如:如果正在写数据文件分析器,可能会在遇到错误时引发语法错误异常,此外也传入一个对象,把行号和文件信息提供给处理器。

这是很有用的,因为异常引发时,也许会跨越任意的文件边界:触发异常的raise语句以及进行捕捉的try语句,也许位于完全不同的文件中,一般来说:无法把额外的细节存储在广域变量内,因为try语句可能不知道广域变量位于哪个文件中。和异常本身一起吧额外的数据传递进去,可让try语句读取时,更有把握。 就像函数的返回值:

每个异常都有这个额外的数据,如果没有刻意的传递什么时,就默认为特殊的None对象.

class MyException(Exception): pass

def raiser1():
    raise MyException, 'Pass Extra Data to Raiser.'

def raiser2():
    raise MyException

def tryer(func):
    try:
        func()
    except MyException, extrainfo:
        print 'got this', extrainfo

tryer(raiser1)
tryer(raiser2)

运行结果:

>>>

got this Pass Extra Data to Raiser.

got this

【利用raise传递异常】

raise语句不包括异常名称或额外值时,就是重新引发当前异常。如果需要捕捉和处理一个异常,又不希望异常在程序代码中死掉,一般就会使用这种方式.

>>> try:
...   raise IndexError, 'spam'
... except IndexError:
...   print 'raise pass exception to top cather!'
...   raise
...
raise pass exception to top cather!
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
IndexError: spam

通过这种方式执行raise时,会重新引发异常,并将其传递给更高层的处理器,或者顶层默认的处理器,也就是停止程序,打印标准错误消息。

【assert语句】

这是raise常见使用模式的语法简写,可视为带条件的raise语句。语句格式为:

assert <test>, <data>         #<data>部分可选

比如下面例子:

如果断言成立的话,不会触发异常

>>> myStr = ‘spam‘

>>> assert len(myStr) > 1, ‘The length of string is more than 1‘

>>> assert range(4)==[0,1,2,3]

>>> assert 1 == 1

如果断言不成立的话,则触发AssertionError的异常

>>> assert len(myStr) > 10, ‘The length of string is more than 1‘

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

AssertionError: The length of string is more than 1

所以其语法等价于:

if __debug__:

if not <test>:

raise AssertionError,<data>

【assert作用】

assert主要是收集约束条件,而不是错误或异常!assert语句是用于验证开发期间程序状况的。

显示时,其错误信息正文会自动包括源代码的行信息。以及列在assert语句中的值。如下例

#File: asserter.py

def func(x):

assert x < 0, ‘x must be negative!‘

return x ** 2

执行结果:

>>> from asserter import *

>>> func(1)

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

File "asserter.py", line 2, in func

assert x < 0, ‘x must be negative!‘

AssertionError: x must be negative!

牢记一点:assert都是用来收集用户定义的约束条件的,而不是捕捉内在的程序设计错误的。因为PYTHON会自动收集程序的设计错误,通常来说是没有必要写assert去捕捉超出索引值,类型不匹配以及除数为0之类的事情。比如说下面:

def func(x,y):

assert x !=0       #这是没有必要的,PYTHON会自动处理

return x / y       #被除数为0的情况.

【with/as环境管理器】

从PYTHON2.6开始,引入的新的异常相关的语句: with以及可选的as分句。这个语句的设计是为了和环境管理器对象一起工作。

简而言之:with/as语句的设计是作为常见try/finally用法模式的替代方案。 就像try/finally语句,with/as语句也是用于定义必须执行的终止或清理行为,无论处理步骤中是否发生异常。和try/finally不同的是,with语句支持更丰富的基于对象的协议,可以为代码块定义支持进入或离开的动作。

PYTHON以环境管理器强化一些内置工具,例如,自动关闭打开的文件,以及对锁的自动上锁和开锁。程序员也可以用类编写自己的环境管理器。

【with/as用法】

因with/as是PYTHON2.6才开始使用的,所以2.5及之前的版本需要导入:

>>> from __future__ import with_statement

语句格式如下:

with experssion [as variable]:   #as为可选

with-block

这里expression要返回一个对象,从而支持环境管理协议

如果选用as分句时,此对象也可返回一个值,将其赋值给变量名variable

NOTE:

1. variable并非赋值为experssion的结果。

2. expression的结果是支持环境协议的对象,而variable则是赋值为其他的东西

3. experssion返回的对象可在with-block开始前,先执行启动程序,并且在该代码完成后,执行终止程序代码,无论该代码块是否引发异常。

with open(r‘data.txt‘) as myfile:

for line in myfile:

print line

或者其他支持环境管理的协议:

lock = threading.Lock()

with lock:

with-block

【PYTHON中常用异常处理测试模块】

def doStuff():

doFirstthing()

doSecondthing()

doLastthing()

def goodEnd(): pass

def badEnding(): pass

if __name__== ‘__main__‘:

try:

doStuff()

except:

badEnding()

else:

goodEnding()

finally:

file.close()

conn.close()

【PYTHON异常语句】

简单来说:

try:     是捕捉

raise:   是触发

assert:  是条件式引发

with:    是把代码块包装在环境管理器中,而从定义进入和离开的行为

【with/as实际例子】

【类异常特点】

和旧的字符串异常模型相比,类异常有如下特点

. 提供类型分类,对今后的修改有更好的支持:新增异常时,不需要在try语句中进行修改

. 提供了存储在try处理器中所使用的环境信息的合理地点:这样的话,可以拥有状态信息以及可调用的方法,并且可以通过实例进行读取

. 允许异常参与继承层次,从而获得共同的行为。例如:继承的显示方式可提供通用的错误信息的外观。

基于类的异常支持了程序的演进和较大系统,从这方面讲,它远优于基于字符串的异常.

【字符串异常】

PYTHON2.5之前的版本,还可以

>>> myexc = "My exception string"

>>> try:

...   raise myexc

... except myexc:

...   print ‘caught‘

caught

之后的版本,显示异常:

Traceback (most recent call last):

File "<stdin>", line 2, in <module>

TypeError: exceptions must be old-style classes or derived from BaseException, not str

【基于类的异常】

字符串和类异常的主要区别在于,引发的异常在try语句中的except分句匹配时的方式不同。

. 前者是以简单对象识别来匹配的:引发的异常是由PYTHON的is测试来匹配except分句的

. 后者是由超类关系进行匹配:只要except分句列举了异常的类,或其任何超类名,引发的异常就会匹配该分句

当try语句的except分句列出一个超类时,就可以捕捉该超类的实例,以及类树中所有较低位置的子类的实例。结果就是类异常支持异常的层次架构:超类变成分类的名称,而子类变成了这个分类中的异常。except分句列出一个通用的异常超类,就可以捕捉整个分类中的各种异常:任何特定的子类都可匹配。

【类异常例子】

#File: classexc.py

class Super:        pass
class Sub01(Super): pass
class Sub02(Super): pass

def raiser0():
    X = Super()
    raise X

def raiser1():
    X = Sub01()
    raise X

def raiser2():
    X = Sub02()
    raise X

for func in (raiser0,raiser1,raiser2):
    try:
        func()
    except Super:      #匹配父类及子类
        import sys
        print 'caught:',sys.exc_info()[0]

执行结果:

C:\>python classexc.py

>>>

caught: __main__.Super

caught: __main__.Sub01

caught: __main__.Sub02

NOTE:

1. sys.exc_info调用,这是一种抓取最近发生异常的常见方式

2. 引发基于类的异常,一定要有个实例

3. PYTHON官方文档之处,自定义类最后继承自Exception

class Super(Exception): pass

【内置Exception类】

1. 所有熟悉的异常(如:IndexError,SyntaxError)其实都是预定义的类,可以作为内置变量名,放在__builtin__模块中.

2. 以及作为标准库模块exceptions的属性。

3. PYTHON把内置异常组织成层次,来支持各种捕捉模式

Exception: 异常的顶层根超类

|

StandardError: 所有内置错误异常的超类

|

ArithmeticError: 所有数值错误的超类

|

OverflowError: 识别特定的数值错误的子类

查询办法:

>>> import exceptions

>>> help(exceptions)

>>> dir(exceptions)

【定义异常文本】

对于未被捕获的类异常,消息包含什么呢? 在默认的情况下,得到的是类的名称以及被抛出的实例对象。

>>> class MyBad: pass

...

>>> raise MyBad()

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

__main__.MyBad: <__main__.MyBad instance at 0x000000000285A608>

上述显示不太美观,作为改进,可以用__repr__,__str__重载函数方法,来重写自己想要的默认异常结果:

>>> class MyBad:

...   def __repr__(self):

...     print ‘Sorry,My mistake!‘

...

>>> raise MyBad()

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

__main__.MyBadSorry,My mistake!

NOTE:另外一种情况,如果我们的类继承自内置异常类,错误显示会发生微妙的改变,因为构造方法参数会自动存储并显示在消息中,如下:

>>> class MyBad(Exception): pass

...

>>> raise MyBad()

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

__main__.MyBad

>>> class MyBad(Exception): pass

...

>>> raise MyBad(‘This‘,‘is‘,‘super‘,‘exception‘,‘test!‘)

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

__main__.MyBad: (‘This‘, ‘is‘, ‘super‘, ‘exception‘, ‘test!‘)

【类的额外数据传递】

分析数据文件的程序可能引发异常实例(填入有关错误的额外细节)从而发出格式错误的信号

class FormatError:                  #格式化错误
    def __init__(self,line,file):
        self.line = line
        self.file = file

def parser():
    #When error found
    raise FormatError(42,file='spam.txt')

try:
    parser()
except FormatError, X:
    print 'Error at', X.line,X.file

在except分句中,变量X赋值为异常引发时所产生的实例。上述的传递异常的额外数据,用字符串的方式也可以实现,但是如果类有行为时,类这种方法可能更方便些

class FormatError:
    def __init__(self,line,file):
        self.line = line
        self.file = file
    def logerror(self):
        log = open('formaterror.txt','a')
        print >> log, 'Error at', self.file, self.line

def parser():
    raise FormatError(40,'spam.txt')

try:
    parser()
except FormatError, exc:
    exc.logerror()

【raise语句的一般格式】

raise语句有5种形式,前两者是引发字符串异常,后两个是引发类异常,而最后一个是重新引发当前异常

raise string           #匹配对象为string的异常

raise string,data      #在上面的基础上再传递额外的数据

raise instance         #如: raise instance.__class__.instance

raise class,instance   #匹配该异常类及她的超类

raise                  #重新触发异常,如果需要传递任意的异常时,就有用处

比如说,要触发KeyError的异常可以用以下几种方式之一:

raise KeyError()         #正常格式: 触发一个实例

raise KeyError,KeyError  #类,实例: 使用实例

raise KeyError           #类:一个实例将要产生

raise KeyError,‘spam‘    #类,变量:一个实例将要产生

而下面的raise,则是将X赋值给了引发的KeyError实例对象

try: pass

except KeyError, X: pass

【PYTHON将不再使用基于字符串的异常】

Guido说:在未来PYTHON版本会消失。这样做的理由:

基于字符串的异常不支持分类、状态信息或行为继承,不像基于类的异常。在程序规模比较小时,还比较容易使用,一旦程序规模变大,就变得难以使用了。

【嵌套异常处理器】

try/except语句:

try/finally语句:

【try/except嵌套例子】

#File: exec.py
def action1():
    print 1 + []             #通常的类型错误

def action2():
    try:
        action1()
    except TypeError:        #最近的找到的匹配错误
        print 'inner error'

try:
    action2()
except TypeError:
    print 'outer error'

执行结果:

C:\>python exec.py

inner error

这里有两个激活的try语句,一个在action1内,一个在action2内。PYTHON会挑选并执行except最近的try,本例子中就是action1()中的try.

【语法嵌套化例子】

上面的代码给下面的等价

def action1():
    print 1 + []

try:
    try:
        action1()
    except TypeError:
        print 'inner try'
except TypeError:
    print 'outer try'

如果换成为try/finally,代码如下:

try:
    try:
        raise TypeError
    finally:
        print 'inner try'
finally:
    print 'outer try'

执行结果:

>>>
inner try
outer try

Traceback (most recent call last):
  File "D:\python\test.py", line 3, in <module>
    raise TypeError
TypeError

下面是try/except/finally嵌套实现的代码及业务逻辑

def raiser1(): return
def raiser2(): raise EOFError
def raiser3(): raise TypeError

for func in (raiser1,raiser2,raiser3):
    print '\n',func
    try:
        try:
            func()
        except TypeError:
            print 'caught TypeError!'
    finally:
        print 'finally run'

执行结果如下:

>>>

<function raiser1 at 0x000000000256E748>

finally run

<function raiser2 at 0x0000000002DDB0B8>

finally run

Traceback (most recent call last):

File "D:\python\test.py", line 8, in <module>

func()

File "D:\python\test.py", line 2, in raiser2

def raiser2(): raise EOFError

EOFError

【异常不总是错误】

在PYTHON中错误都是异常,但异常不总是错误。比如对文件对象进行读取操作,文件末尾会有空字符,sys.stdin读取末尾的空字符串行会报EOFError的异常,这不是错误,是正常行为。除非放到try,并放到嵌套的循环内,如:

while 1:

try:

line = raw_input(‘Enter here:‘)

except EOFError:

break

else:

...

【函数信号条件和raise】

用户定义的异常也可引发非错误的情况。比如:搜索程序可以写成找到相符者引发异常,而不是为调用者返回状态标志来拦截。在下面的代码中,try/except/else处理器做的就是if/else返回值的测试工作

class Found(Exception): pass

def searcher():
    if ...success...:
        raise Found()
    else:
        return

try:
    searcher()
except Found:
    ...success...
else:
    ...failure...

如果所有对象都是可能的有效返回值,就不可能以任何返回值来代表不寻常的情况。异常则提供了一种方式来传达结果讯息,而不使用返回值,如下例

class Failure(Exception): pass

def searcher():
    if ...success...
        return ...founditem...
    else:
        raise Failure()

try:
    item = searcher()
except Failure:
    ...report...
else:
    ...use item here...

因为PYTHON核心是动态类型和多态的,通常更趋向于使用异常来发出这类情况的信号,而不是警示性的返回值。

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

【】

时间: 2024-10-23 12:12:17

Python 点滴 V的相关文章

python 点滴记录6:ubuntu 安装pycharm

想在ubuntu下学习python开发,IDE准备使用pycharm.记录一下安装过程: 要想运行pycharm,需要有java环境,因为pycharm是用java编写的.ubunutn系统默认安装的是openjdk,而我们需要的是oracle java. 搜索oracle的java软件包: apt-cache search oracle-java 搜不到任何包. 搜索openjdk包: apt-cache search java7 出现类似以下安装包: openjdk-7-jdk - Open

Python 点滴 I

[为什么使用Python] 1. 软件质量 2. 开发效率 3. 可移植性 4. 标准库支持 5. 好玩 [Python全景] #模块,语句,表达式,对象) 1. 程序由模块组成 2. 模块包含语句 3. 语句包含表达式 4. 表达式建立并处理对象 [动态类型] Python即是动态类型又是强类型,在C/C++/Java强类型语言中,要先声明,后使用 动态类型:自动跟踪用户定义的类型而不需要预先定义 s=1的话, s*2就等于2 s='hello'的话, s*2就等于'hellohello' [

Python 点滴 II

[__doc__] >>> str.__doc__         #内置文档字符串; 模块级 "str(object='') -> string\n\nReturn a nice string representation of the object.\nIf the argument is a string, the return value is the same object." >>> str.upper.__doc__   #内置文

python 点滴记录15:MAC OS安装MySQLdb

下载安装包:http://sourceforge.net/projects/mysql-python然后解压. 切换到目录下执行 python setup.py install 报错: EnvironmentError: mysql_config not found 解决:在安装包中找到site.cfg文件,将 #mysql_config =/usr/local/bin/mysql_config 修改为: mysql_config =/usr/local/mysql/bin/mysql_conf

Python 点滴 III

[Python模块的角色] 代码重用 系统命名空间的划分 实现共享服务和数据 [import模块工作步骤] 在Python中,导入并非只是如C中#include一样:把一个文件插入另外一个文件.程序第一次导入时,会执行三个步骤. 1. 找到模块 2. 编译成位码(需要时) 3. 执行模块的代码来创建其所定义的对象 [模块搜索路径] 按执行的先后顺序 1. 程序的主目录 2. PYTHONPATH目录 3. 标准链接库目录 4. 任何.pth文件的内容 这四个组件组合起来就变成了sys.path

Python 点滴 IV

[继承示意图] 类是实例的工厂, OOP就是在树中搜索属性,类事实上就是变量名与函数打成的包 . 每一个class语句会生成一个新的类对象 . 每次类调用时,就会生成一个新的实例对象 . 实例自己主动连接到创建这些实例的类 . 类连接到超类的方式是,将超类列在类头部(),其从左到右的顺序会决定树中的次序 有几点须要注意: . 属性一般是在class语句中通过赋值语句加入在类中,而不是嵌入函数的def语句中 . 属性一般是在类中,对传给函数的特殊參数self.做赋值运算而加入在实例中的 [方法调用

【Python】Python点滴(一)——pip工具使用

首先我们来看一条命令:pip install uwsgi 这条命令按照操作名称,可以分为三个部分:pip.install和uwsgi.接下来,按照这样三个部分进行分析. pip pip类似于ReadHat下的yum.Ubuntu下的apt-get,一个包管理工具,用来下载安装Python一个公共资源库PyPI的相关资源包.同样的一个工具还有easy_install. Note: 1.easy_install下载地址:https://pypi.python.org/pypi/ez_setup 解压

python 点滴记录12:异常处理

引入异常处理机制,使得运行的程序发生错误时,不至于崩溃. 常见格式: try:     command 1 except:     command 2 当command 1 执行出错时,就会执行command 2.command 2 通常是自己定义的错误提示或者系统默认的提示. eg: #!/usr/bin/python while 1:         c = raw_input("input 'c' continue,otherwise logout:")         if c

python点滴

self python的类方法与普通函数有一显著区分,方法必须有第一个参数self,self表示该类的实例本身(不是类本身!),存储该对象的地址:相当于C++中的self指针.Java/C#中的this. 为何要self,举例说明: class Foo: def m(self, x, y): ... 可以如下引用m: Foo.__dict__['m'] 或 Foo.m.__func__ 但因为Foo是类,m作为方法必须与对象绑定,所以对象self要作为参数传入.