分享
 
 
 

Python指南--错误和异常

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

子目录

8.1 语法错误

8.2 异常

8.3 处理异常

8.4 抛出异常

8.5 用户自定义异常

8.6 定义清理行为

8. 错误和异常

至今为止还没有进一步的谈论过错误信息,不过在你已经试验过的那些例子中,可能已经遇到过一些。Python中(至少)有两种错误:语法错误和异常( syntax errors and exceptions)。

8.1 语法错误

语法错误,也称作解析错误,可能是学习Python的过程中最容易犯的:

>>> while True print 'Hello world'

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

while True print 'Hello world'

^

SyntaxError: invalid syntax

解析器会重复出错的行,并在行中最早发现的错误位置上显示一个小箭头。错误(至少是被检测到)就发生在箭头指向的位置。示例中的错误表现在关键字print上,因为在它之前少了一个冒号(:)。同时也会显示文件名和行号,这样你就可以知道错误来自哪个脚本,什么位置。

8.2 异常

即使是在语法上完全正确的语句,尝试执行它的时候,也有可能会发生错误。在程序运行中检测出的错误称之为异常,它通常不会导致致命的问题,你很快就会学到如何在Python程序中控制它们。大多数异常不会由程序处理,而是显示一个错误信息:

>>> 10 * (1/0)

Traceback (most recent call last):

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

ZeroDivisionError: integer division or modulo by zero

>>> 4 + spam*3

Traceback (most recent call last):

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

NameError: name 'spam' is not defined

>>> '2' + 2

Traceback (most recent call last):

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

TypeError: cannot concatenate 'str' and 'int' objects

错误信息的最后一行指出发生了什么错误。异常也有不同的类型,异常类型做为错误信息的一部分显示出来:示例中的异常分别为零除错误( ZeroDivisionError ),命名错误( NameError)和类型错误( TypeError )。打印错误信息时,异常的类型作为异常的内置名显示。对于所有的内置异常都是如此,不过用户自定义异常就不一定了(尽管这是一个很有用的约定)。标准异常名是内置的标识(没有保留关键字)。

这一行后一部分是关于该异常类型的详细说明,这意味着它的内容依赖于异常类型。

错误信息的前半部分以堆栈的形式列出异常发生的位置。通常在堆栈中列出了源代码行,然而,来自标准输入的源码不会显示出来。

Python 库参考手册 列出了内置异常和它们的含义。

8.3 处理异常

通过编程可以处理指定的异常。以下的例子重复要求用户输入一个值,直到用户输入的是一个合法的整数为止。不过这个程序允许用户中断程序(使用 Control-C 或者其它操作系统支持的方法)。需要注意的是用户发出的中断会引发一个 KeyboardInterrupt 异常。

>>> while True:

... try:

... x = int(raw_input("Please enter a number: "))

... break

... except ValueError:

... print "Oops! That was no valid number. Try again..."

...

try 语句按如下方式工作:

首先,执行 try 子句(在try 和 except关键字之间的部分)。

如果没有异常发生,except 子句 在try语句执行完毕后就被忽略了。

如果在try子句执行过程中发生了异常,那么该子句其余的部分就会被忽略。如果异常匹配于except关键字后面指定的异常类型,就执行对应的except子句,忽略try子句的其它部分。然后继续执行try语句之后的代码。

如果发生了一个异常,在except子句中没有与之匹配的分支,它就会传递到上一级try语句中。如果最终仍找不到对应的处理语句,它就成为一个未处理异常,终止程序运行,显示提示信息。

一个try 语句可能包含多个 except 子句,分别指定处理不同的异常。至多只会有一个分支被执行。异常处理程序只会处理对应的try子句中发生的异常,在同一个try语句中,其他子句中发生的异常则不作处理。一个except子句可以在括号中列出多个异常的名字,例如:

... except (RuntimeError, TypeError, NameError):

... pass

最后一个except子句可以省略异常名,把它当做一个通配项使用。一定要慎用这种方法,因为它很可能会屏蔽掉真正的程序错误,使人无法发现!它也可以用于打印一行错误信息,然后重新抛出异常(可以使调用者更好的处理异常)。

import string, sys

try:

f = open('myfile.txt')

s = f.readline()

i = int(string.strip(s))

except IOError, (errno, strerror):

print "I/O error(%s): %s" % (errno, strerror)

except ValueError:

print "Could not convert data to an integer."

except:

print "Unexpected error:", sys.exc_info()[0]

raise

try ... except 语句可以带有一个 else 子句, 该子句只能出现在所有except子句之后。当try语句没有抛出异常时,需要执行一些代码,可以使用这个子句。例如:

for arg in sys.argv[1:]:

try:

f = open(arg, 'r')

except IOError:

print 'cannot open', arg

else:

print arg, 'has', len(f.readlines()), 'lines'

f.close()

使用 else 子句比在 try 子句中附加代码要好,因为这样可以避免 try ... except 意外的截获本来不属于它们保护的那些代码抛出的异常。

发生异常时,可能会有一个附属值,作为异常的参数存在。这个参数是否存在、是什么类型,依赖于异常的类型。

在异常名(列表)之后,也可以为 except 子句指定一个变量。这个变量绑定于一个异常实例,它存储在 instance.args 的参数中。为了方便起见,异常实例定义了 __getitem__ 和 __str__ ,这样就可以直接访问过打印参数而不必引用 .args。

>>> try:

... raise Exception('spam', 'eggs')

... except Exception, inst:

... print type(inst) # the exception instance

... print inst.args # arguments stored in .args

... print inst # __str__ allows args to printed directly

... x, y = inst # __getitem__ allows args to be unpacked directly

... print 'x =', x

... print 'y =', y

...

<type 'instance'>

('spam', 'eggs')

('spam', 'eggs')

x = spam

y = eggs

对于未处理的异常,如果它有一个参数,那做就会作为错误信息的最后一部分(“明细”)打印出来。

异常处理句柄不止可以处理直接发生在try子句中的异常,即使是其中(甚至是间接)调用的函数,发生了异常,也一样可以处理。例如:

>>> def this_fails():

... x = 1/0

...

>>> try:

... this_fails()

... except ZeroDivisionError, detail:

... print 'Handling run-time error:', detail

...

Handling run-time error: integer division or modulo

8.4 抛出异常

在发生了特定的异常时,程序员可以用 raise 语句强制抛出异常。例如:

>>> raise NameError, 'HiThere'

Traceback (most recent call last):

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

NameError: HiThere

第一个参数指定了所抛出异常的名称,第二个指定了异常的参数。

如果你决定抛出一个异常而不处理它,raise 语句可以让你很简单的重新抛出该异常。

>>> try:

... raise NameError, 'HiThere'

... except NameError:

... print 'An exception flew by!'

... raise

...

An exception flew by!

Traceback (most recent call last):

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

NameError: HiThere

8.5 用户自定义异常

在程序中可以通过创建新的异常类型来命名自己的异常。异常类通常应该直接或间接的从 Exception 类派生,例如:

>>> class MyError(Exception):

... def __init__(self, value):

... self.value = value

... def __str__(self):

... return repr(self.value)

...

>>> try:

... raise MyError(2*2)

... except MyError, e:

... print 'My exception occurred, value:', e.value

...

My exception occurred, value: 4

>>> raise MyError, 'oops!'

Traceback (most recent call last):

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

__main__.MyError: 'oops!'

异常类中可以定义任何其它类中可以定义的东西,但是通常为了保持简单,只在其中加入几个属性信息,以供异常处理句柄提取。如果一个新创建的模块中需要抛出几种不同的错误时,一个通常的作法是为该模块定义一个异常基类,然后针对不同的错误类型派生出对应的异常子类。

class Error(Exception):

"""Base class for exceptions in this module."""

pass

class InputError(Error):

"""Exception raised for errors in the input.

Attributes:

expression -- input expression in which the error occurred

message -- explanation of the error

"""

def __init__(self, expression, message):

self.expression = expression

self.message = message

class TransitionError(Error):

"""Raised when an operation attempts a state transition that's not

allowed.

Attributes:

previous -- state at beginning of transition

next -- attempted new state

message -- explanation of why the specific transition is not allowed

"""

def __init__(self, previous, next, message):

self.previous = previous

self.next = next

self.message = message

与标准异常相似,大多数异常的命名都以“Error”结尾。

很多标准模块中都定义了自己的异常,用以报告在他们所定义的函数中可能发生的错误。关于类的进一步信息请参见第 9章,“类”。

8.6 定义清理行为

try 语句还有另一个可选的子句,目的在于定义在任何情况下都一定要执行的功能。例如:

>>> try:

... raise KeyboardInterrupt

... finally:

... print 'Goodbye, world!'

...

Goodbye, world!

Traceback (most recent call last):

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

KeyboardInterrupt

不管try子句中有没有发生异常, finally 子句都一定会被执行。如果发生异常,在finally子句执行完后它会被重新抛出。 try 子句经由

break 或 return 退出也一样会执行finally 子句。

在finally 子句中的代码用于释放外部资源(例如文件或网络连接),不管这些资源是否已经成功利用。

在 try 语句中可以使用若干个 except 子句或一个 finally 子句,但两者不能共存。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有