Python 错误与异常

错误和异常

语法错误

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

In: while True print('Hello World')
Out:
File "<stdin>", 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 "<stdin>", line 1, in <module>
    File "<stdin>", 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 "<stdin>", line 2, in <module>
  File "<stdin>", 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 <module>
    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 "<stdin>", line 1, in <module>
__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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343