# 异常概念

异常机制提高程序的健壮性,使用程序有更好的容错性。来看一个异常处理的样例:

import sys
try:
    print(sys.argv[0])
    a = int(sys.argv[1])
    b = int(sys.argv[2])
    c = a / b
    print("a/b:%s" % c)

except ZeroDivisionError:
    print("除数是0!")

except (ValueError,IndexError):
    print("输入得到不是整数或者输入的参数不够!")

except Exception:
    print("其他异常错误!")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 异常继承关系

注意捕获的异常应该由小到大,不同异常之间也是有继承关系的,应该先写最底层的异常,这样可以明确出问题后是哪方面的问题,异常之间的继承关系如下:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

引用自Python官方文档 Exception-hierarchy

# 访问异常信息

Python解释器决定调用某个except块时,会将异常对象赋值给except块后的异常变量,程序可通过该变量获取相关信息,所有的异常对象基本都包含下面几个属性和方法:

  • args:返回异常的错误编号和描述字符串。
  • errno:返回异常的错误编号。
  • strerror:返回异常的描述字符串。
  • with_traceback():获取异常的堆栈信息。
import sys
try :
    f = open("temp.txt")
except Exception as e:
    print(e.args)
    print(e.errno)
    print(e.strerror)
    raise e.with_traceback(sys.exc_info()[2])
1
2
3
4
5
6
7
8

# else和finally

看实例:

try:
    result = 10/5
except ZeroDivisionError:
    print("发生异常,除数是0!")
else:
    print("正常执行")
1
2
3
4
5
6

else代码块的意义是只有在执行try代码块时没有发生异常才执行else代码块。

def TestFunc():
    try:
        a=10/0
        return True
    except ZeroDivisionError:
        print("分母为0")
    else:
        print("程序正常执行")
    finally:
        print("执行finally代码块")
        return False

print(TestFunc())
1
2
3
4
5
6
7
8
9
10
11
12
13

当代码块没有发生异常时吗,不会执行else代码块会直接执行finally代码块,当代码块发生异常时,执行完异常再执行finally代码块。

注意不要在finally代码块写return或raise语句,这样导致try代码块中的return失效。

# raise语句

我们可以主动触发异常,一般用于自定义的异常类,来看下raise的用法:

class MyException(Exception):pass

try:
    print("this is a block!")
    raise MyException
except MyException:
    print("This is my exception!")
1
2
3
4
5
6
7

# 查看异常堆栈

import traceback
import sys

class MyExcept(Exception):pass

def F1():
    F2()
def F2():
    F3()
def F3():
    F4()
def F4():
    raise MyExcept("Test Exception Stack")

try:
    F1()
except:
    #print(traceback.format_exc())
    traceback.print_exc(limit=2,file=open("temp.txt",'a'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 异常处理原则

异常处理需要有几个原则:

  1. 不要过度使用异常。不要把错误当成异常来处理。
  2. 不要使用过于庞大的try块。
  3. 不要忽略捕获的异常。