欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第八章 异常

程序员文章站 2022-06-15 22:46:39
...

8.1 什么是异常(异常都是立马执行的)

python用异常对象(exception object)表示异常情况。遇到错误后,会引发异常。如果异常对象未被处理或捕捉,程序就会用回溯(traceback,一种错误信息)终止执行。每个异常都是一些类的实例

8.2  按自己方式出错

8.2.1    raise

使用一个类(Exception的子类)或实例参数调用raise

 捕捉异常并且进行处理,而不让整个程序崩溃

>>> raise Exception

Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    raise Exception
Exception
>>> raise Exception("hyperdrive overload")#添加错误信息

Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    raise Exception("hyperdrive overload")#添加错误信息
Exception: hyperdrive overload

可以添加错误信息
可以使用dir(exceptions)  列出内建异常 

表8-1描述了一些最重要的内建异常类:

表8-1 一些内建异常类

 

Exception            所有异常的基类

AttributeError           特性引用或赋值失败时引发

IOError             试图打开不存在文件(包括其他情况)时引发

IndexError                                         在使用序列中不存在的索引时引发

KeyError              在使用映射中不存在的键时引发

NameError             在找不到名字(变量)时引发

SyntaxError            在代码为错误形式时引发

TypeError             在内建操作或者函数应用于错误类型的对象时引发

ValueError            在内建操作或者函数应用于正确类型的对象,但是该对象使用不合适的值时引发

ZeroDivisionError         在除法或者模除操作的第二个参数为0时引发


8.2.2 自定义异常类型

      为什么要自定义?
可以根据异常所在的类,选择性地处理当前类型的异常。所以如果想要用特殊的错误处理代码处理错误,就要自定义一个异常类。
如何创建?
确保自
定义类是从Exception类继承的(直接或者间接)

class SomeCustomException(Exception): pass


8.3    捕捉异常(处理异常)
重点   使用.    try....except
Enter the first number: 10
Enter the second number: 0
Traceback (most recent call last):
  File "/home/marlowes/MyPython/My_Exception.py", line 6, in <module>
    print x / y
ZeroDivisionError: integer division or modulo by zero

使用try.....except
try:
    x = input("Enter the first number: ")
    y = input("Enter the second number: ")
    print x / y
except ZeroDivisionError:
    print "The second number can't be zero!"
让错误发生时,执行别的语句
比if要好,因为只要写一个错误处理器.

注:如果没有捕捉异常,它就会被“传播”到调用的函数中。如果在那里依然没有捕获,这些异常就会“浮”到程序的最顶层,也就是说你可以捕捉到在其他人的函数中所引发的异常。有关这方面的更多信息,请参见8.10节。    8.10(看不懂,之后再来看

异常的抛出机制:

1、如果在运行时发生异常,解释器会查找相应的处理语句(称为handler.

2、要是在当前函数里没有找到的话,它会将异常传递给上层的调用函数,看看那里能不能处理。

3、如果在最外层(全局“main”)还是没有找到的话,程序会带着栈跟踪终止,同时打印出traceback以便让用户找到错误产生的原因。

 

>>> 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 "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in ignore_exception
  File "<stdin>", line 2, in faulty
Exception: Something is wrong
>>> handle_exception()
Exception handled
可以看到,faulty中产生的异常通过faulty->ingore_exception传播,最终导致栈跟踪,handle_exception同理


如果捕捉到了异常,但是又想重新引发它(也就是说要传递异常,不进行处理),那么可以调用不带参数的raise(还能在捕捉到异常时显式地提供具体异常,在8.6节会对此进行解释)。          重新把异常继续向上传递。


作用:举个例子吧,看看这么做多么有用:考虑一下一个能“屏蔽”ZeroDivisionError(除零错误)的计算器类。如果这个行为被**,那么计算器就打印错误信息,而不是让异常传播(说明没except异常)。如果在与用户交互的过程中使用,那么这就有用了,但是如果是在程序内部使用,引发异常会更好些。因此“屏蔽”机制就可以关掉了,下面是这样一个类的代码:

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   #关闭屏蔽


注:如果除零行为发生而屏蔽机制被打开,那么calc方法会(隐式地)返回None。换句话说,如果打开了屏蔽机制,那么就不应该依赖返回值。

8.4 使用多个except

1.使用多个子句

2.使用元组包含多个异常类型


8.6 捕捉对象

在except子句中访问异常对象本身

 显示的捕捉对象本身

下面的示例程序会打印异常(如果发生的话),但是程序会继续运行:

try:
    x = input("Enter the first number: ")
    y = input("Enter the second number: ")
    print x / y
except (ZeroDivisionError, TypeError), e:#as e     在python3.0中
    print e

8.7 全捕捉

直接使用 except:    (不加入错误类型),捕捉所有异常

危险

可以使用 except Exception,e:      会更好,这样可以对e做一些检查

8.8 else

没出现错误时,执行else

8.9 finally

不管异常是否发生,都执行

通常用来清理

x = None
try:
    x = 1 / 0
finally:
    print "Cleaning up..."
    del x

在程序traceback之前,清理就已经完成。