Python 错误与异常

错误和异常

语法错误

语法错误, 也被称为解析错误。比如:

In: while True print('Hello World')
Out:
File "", line 1
  while True print('Hello World')
                 ^
SyntaxError: invalid syntax

语法分析器指出错误行, 并且在检测到错误的位置前面显示一个小“箭头”。 错误是由箭头指向的标记引起的(或者至少是这么检测的): 这个例子中, 函数 print() 被发现存在错误, 因为它前面少了一个冒号:。错误会输出文件名和行号, 所以如果是从脚本输入的你就知道去哪里检查错误了。

异常

即使代码在语法上是正确的, 但是执行它的时候可能会引发一些错误。运行期间检测到的错误称为 异常。大多数的异常都不会被程序处理, 会以错误信息的形式展示出来。下面是一个异常的例子:

In: def div(a, b):
...     return a / b

In: div(1, 0)
Out:
Traceback (most recent call last):
    File "", line 1, in 
    File "", line 2, in div
ZeroDivisionError: division by zero

异常以不同的类型出现,这些类型都作为信息的一部分打印出来, 例如上面这个例子的类型是 ZeroDivisionError

错误信息的前面部分显示了异常发生的上下文,并以调用栈的形式显示具体信息。

异常处理

try-except 代码块可以捕获异常, try/except 语句用来检测 try 语句块中的错误, 从而让 except 语句捕获异常信息并处理, 这样异常在捕获后, 只会执行设定的处理方案。

如果不想程序在异常发生时结束, 可以在 try 里面捕获异常。

下面是 try-except 的简单语法:

try:
    <语句>        # 运行别的代码
except <名字>:
    <语句>        # 如果在try部份引发了'name'异常
except <名字>, <数据>:
    <语句>        # 如果引发了'name'异常,获得附加的数据
else:
    <语句>        # 如果没有异常发生

在上一节(异常)中的代码使用 try-except 这样处理:

In: try:
...     div(1, 0)
... except ZeroDivisionError:
...     print('除数不能为0!')

Out:
除数不能为0!

还可以捕获多种异常类型, 可以把需要捕获的异常类型放到 tuple(元组) 里面:

In: l = []

In: try:
...     l[1]
... except (IndexError, ValueError):
...     print('Oops!')

Out:
Oops!

except 可以有多个, 不同的异常使用不同的处理方案:

In: try:
...     l[1]
... except IndexError:
...     print('index error')
... except ValueError:
...     print('value error')

Out:
index error

try-except-else

try-except-else: 如果 try 代码块执行成功, 没有引发异常, 那么程序会执行 else 代码块中的代码:

In: try:
...     div(1, 0)
... except ZeroDivisionError:
...     print('除数不能为0!')
... else:
...     print('代码成功执行!')

Out:
除数不能为0!

In: try:
...     div(1, 2)
... except ZeroDivisionError:
...     print('除数不能为0!')
... else:
...     print('代码成功执行!')

Out:
0.5
代码执行成功!

try-finally

try-finally: try-finally 语句无论是否发生异常都将执行 finally 的代码:

In: try:
...     div(1, 0)
... finally:
...     print('finally')
...

Out:
finally
Traceback (most recent call last):
  File "", line 2, in 
  File "", line 2, in div
ZeroDivisionError: division by zero

组合 try 语法

将上面的形式合并起来代码如下:

def div(a, b):
    try:
        result = a / b
    except ZeroDivisionError as e: # as 关键字相当于把捕获到的异常加个别名, 在这里是 e
        print(e)
    else:
        print('result is', result)
    finally:
        print('executing finally clause')

In: div(1, 0)
Out:
division by zero
executing finally clause

In: div(1, 2)
Out:
result is 0.5
executing finally clause

不能捕获没有 except 的异常

如果没有捕获一个特定的异常, 而这个异常发生了, 程序还是会发生错误, 比如在上面代码的基础上调用 div(a, b):

In: div('1', 2)

Out:
executing finally clause
Traceback (most recent call last):
  File "E:/develop/dog_book/demo.py", line 17, in 
    div('1', 2)
  File "E:/develop/dog_book/demo.py", line 3, in div
    result = a / b
TypeError: unsupported operand type(s) for /: 'str' and 'int'

使用 except 而不带任何异常类型

except 不捕获特定的异常类, 会表示为捕获全部类型的异常:

In: try:
...     div(1, 0)
... except:
...     print('除数不能为0!')

Out:        
除数不能为0!

这种方法不太可取, 可能会导致一些隐藏的问题, 正确的做法是指定某个或者某些确定的异常。

触发异常

可以使用 raise 语句自己触发异常, raise 语法如下:

raise [Exception [, args [, traceback]]]
# Exception: 异常的类型参数标准异常中的任意一种
# args: 自己提供的异常参数 
# 最后一个参数是可选的, 如果存在, 是跟踪异常对象

用户自定义异常

在程序中可以通过创建新的异常类来命名自己的异常, 异常应该是典型的继承自 Exception 类, 通过直接或间接的方式。

class NetworkError(Exception):
    pass

In: raise NetworkError('network error') # 主动抛出异常
Out:
Traceback (most recent call last):
  File "", line 1, in 
__main__.NetworkError: network error

In: try:
...     raise NetworkError('network error')
... except NetworkError:
...     print('Catch!')

Out:
Catch!

内置异常多以 Error 结尾, 自定义异常建议:

1.以 Exception 后缀表示可修复异常

2.Error 后缀表示不可修复异常

class RequestException(Exception):
    pass

class RequestError(Exception):
    pass

你可能感兴趣的:(Python 错误与异常)