首页 > 代码库 > python基础教程_学习笔记10:异常

python基础教程_学习笔记10:异常

异常

什么是异常

Python用异常对象来表示异常情况。遇到错误后,会引发异常。如果异常对象并未被处理或捕捉,程序就会用所谓的回溯(Traceback,一种错误信息)终止执行:

>>> 1/0

 

Traceback (most recent call last):

  File "<pyshell#0>", line 1, in <module>

    1/0

ZeroDivisionError: integer division or modulo by zero

 

每个异常都是一些类的实例,这些实例可以被引发,并且可以用很多方法进行捕捉,使得程序可以捉住错误并对其进行处理,而不是让整个程序失败。

 

按自己的方式出错

异常可以在某些东西出错时自动引发

raise语句

为了引发异常,可以使用一个类(应该是Exception的子类)或者实例参数调用raise语句。使用类时,程序会自动创建实例。

>>> raise Exception

 

Traceback (most recent call last):

  File "<pyshell#1>", line 1, in <module>

    raise Exception

Exception

>>> raise Exception(‘hyperdrive overload‘)

 

Traceback (most recent call last):

  File "<pyshell#2>", line 1, in <module>

    raise Exception(‘hyperdrive overload‘)

Exception: hyperdrive overload

 

第一个例子引发了一个没有任何有关错误信息的普通异常;

第二个例子则添加了一些hyperdive overload错误信息。

 

内建的异常类有很多。

>>> import exceptions

>>> dir(exceptions)

[‘ArithmeticError‘, ‘AssertionError‘, ‘AttributeError‘, ‘BaseException‘, ‘BufferError‘, ‘BytesWarning‘, ‘DeprecationWarning‘, ‘EOFError‘, ‘EnvironmentError‘, ‘Exception‘, ‘FloatingPointError‘, ‘FutureWarning‘, ‘GeneratorExit‘, ‘IOError‘, ‘ImportError‘, ‘ImportWarning‘, ‘IndentationError‘, ‘IndexError‘, ‘KeyError‘, ‘KeyboardInterrupt‘, ‘LookupError‘, ‘MemoryError‘, ‘NameError‘, ‘NotImplementedError‘, ‘OSError‘, ‘OverflowError‘, ‘PendingDeprecationWarning‘, ‘ReferenceError‘, ‘RuntimeError‘, ‘RuntimeWarning‘, ‘StandardError‘, ‘StopIteration‘, ‘SyntaxError‘, ‘SyntaxWarning‘, ‘SystemError‘, ‘SystemExit‘, ‘TabError‘, ‘TypeError‘, ‘UnboundLocalError‘, ‘UnicodeDecodeError‘, ‘UnicodeEncodeError‘, ‘UnicodeError‘, ‘UnicodeTranslateError‘, ‘UnicodeWarning‘, ‘UserWarning‘, ‘ValueError‘, ‘Warning‘, ‘WindowsError‘, ‘ZeroDivisionError‘, ‘__doc__‘, ‘__name__‘, ‘__package__‘]

 

所有这些异常都可以用于raise语句:

>>> raise ZeroDivisionError

 

Traceback (most recent call last):

  File "<pyshell#6>", line 1, in <module>

    raise ZeroDivisionError

ZeroDivisionError

>>> raise BaseException

 

Traceback (most recent call last):

  File "<pyshell#7>", line 1, in <module>

    raise BaseException

BaseException

 

一些最重要的内建异常类

类名描述
Exception所有异常的基类
AttributeError特性引用或赋值失败时引发
IOError试图打开不存在的文件(包括其他情况)时引发
IndexError在使用序列不存在的索引时引发
KeyError在使用映射中不存在的键时引发
NameError在找不到名字(变量)时引发
SyntaxError在代码为错误形式时引发
TypeError在内建操作或函数应用于错误类型的对象时引发
ValueError在内建操作或者函数应用于正确类型的对象,但该对象使用不合适的值时引发
ZeroDivisionError在除法或模除操作的第二个参数为0时引发

自定义异常类

有些时候需要创建自己的异常类。

class SomeCustomException(Exception): pass

可以向自动义异常类中增加方法,此处什么也没做。

 

捕捉异常

关于异常最有意思的地方就是可以处理它们(通常叫做诱捕或者捕捉异常)。

这个功能可以使用try/except来实现。

 

x=input(‘1st number: ’)

y=input(‘2nd number: ’)

print x/y

 

如果用户输入0作为第二个数,则出现ZeroDivisionError异常。

 

为了捕捉异常并且做出一些错误处理:

try:

x=input(‘1st number: ’)

y=input(‘2nd number: ’)

print x/y

except ZeroDivisionError:

print “The 2nd number can’t be zero!”

 

看,没参数

>>> class MuffledCalculator:

muffled=False

def calc(self,expr):

try:

return eval(expr)

except ZeroDivisionError:

if self.muffled:

print "Division by zero is illegal"

else:

raise

 

>>> calculator=MuffledCalculator()

>>> calculator.calc(‘10/2‘)

5

>>> calculator.calc(‘10/0‘)

 

Traceback (most recent call last):

  File "<pyshell#22>", line 1, in <module>

    calculator.calc(‘10/0‘)

  File "<pyshell#19>", line 5, in calc

    return eval(expr)

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

ZeroDivisionError: integer division or modulo by zero

>>> calculator.muffled=True

>>> calculator.calc(‘10/0‘)

Division by zero is illegal

不止一个except子句

try:

x=input(‘1st number: ’)

y=input(‘2nd number: ’)

print x/y

except ZeroDivisionError:

print “The 2nd number can’t be zero!”

 

如果用户输入“HelloWorld”作为第二个参数,将引发错误:

TypeError: unsupported operand type(s) for /: ‘int‘ and ‘str‘

因为except子句只寻找ZeroDivisionError异常,这次的错误就溜过了检查并导致程序终止。为了捕捉这个异常,可以直接在同一个try/except语句后面加上另一个except子句:

try:

x=input(‘1st number: ’)

y=input(‘2nd number: ’)

print x/y

except ZeroDivisionError:

print “The 2nd number can’t be zero!”

except TypeError:

print “That wasn’t a number,was it?”

用一个块捕捉两个异常

如果需要用一个块捕捉多个类型异常,可以将它们作为元组列出:

 

try:

x=input(‘1st number: ’)

y=input(‘2nd number: ’)

print x/y

except (ZeroDivisionError,TypeError):

print “Your numers are bogus!”

捕捉对象

如果想让程序继续运行,但是又因为某种原因想记录下错误,捕捉对象就很有用。

 

try:

x=input(‘1st number: ’)

y=input(‘2nd number: ’)

print x/y

except (ZeroDivisionError,TypeError),e:

print e

真正的全捕捉

就算程序能处理好几种类型的异常,但有些异常还是会从眼皮底下溜走。

 

以除法为例子,在提示符下直接按回车,不输入任何东西,会得倒一个类似下面的错误信息:

SyntaxError: unexpected EOF while parsing

 

这个异常逃过了try/except语句的检查。这种情况下,与其用那些并非捕捉这些异常的try/except语句隐藏异常,还不如让程序立刻崩溃。

 

但如果真的想用一段代码捕获所有异常,可以在except子句中忽略所有的异常类:

try:

x=input(‘1st number: ’)

y=input(‘2nd number: ’)

print x/y

except:

print ‘Something wrong happened...’

 

警告:像这样捕捉所有异常是危险的,因为它会隐藏所有程序员未想到并且未做好准备处理的错误。它同样会捕捉用户终止执行的Ctrl+c企图,以及用sys.exit函数终止程序的企图,等等。这时用except Exception,e会更好些,或者对异常对象e进行一些检查。

万事大吉

有些情况下,一些坏事发生时执行一段代码是很有用的,可以给try/except语句加个else子句:

>>> try:

print ‘A simple task‘

except:

print ‘what?‘

else:

print ‘nothing‘

 

 

A simple task

nothing

最后......

finally子句,用来在可能的异常后进行清理。

 

>>> try:

print ‘A simple task‘

except:

print ‘what?‘

else:

print ‘nothing‘

finally:

print ‘clean up‘

 

A simple task

nothing

clean up

异常和函数

异常和函数很自然地一起工作。如果异常在函数内引发而不被处理,它会传播至函数调用的地方。如果在那里也没有处理异常,它会继续传播,一直到达主程序(全局作用域)。如果那里没有异常处理程序,程序会带着堆栈跟踪终止。

 

>>> def faulty():

raise Exception(‘something is wrong‘)

 

>>> def ignore_exception():

faulty()

 

>>> def handle_exception():

try:

faulty()

except:

print ‘Exception handled‘

 

>>> ignore_exception()

 

Traceback (most recent call last):

  File "<pyshell#58>", line 1, in <module>

    ignore_exception()

  File "<pyshell#51>", line 2, in ignore_exception

    faulty()

  File "<pyshell#48>", line 2, in faulty

    raise Exception(‘something is wrong‘)

Exception: something is wrong

>>> handle_exception()

Exception handled