《Python基础教程》第8章 异常

本章将学习创建和引发自定义的异常,以及处理异常的各种方法。

8.1 什么是异常

程序运行中的错误或者不期望发生的事情就是异常,为了防止这样的事件你可以使用大量的条件语句,但是这样做的成本会非常高并且没效率。

在Python中,用异常对象(exception object)来表示异常。如果异常对象未被处理或者捕捉,程序就会使用回溯(Traceback,一种错误信息)来终止程序。事实上每个异常都是一些异常类的实例,异常类的实例在不同情况被引发,并且都能够被捕捉到后进行错误处理,而不至于程序运行失败。

8.2 按自己的方式出错

8.2.1 raise语句

有很多内建的异常类,详细介绍可以查询Python的文档“Built-in Exception”相关部分。

可以使用dir列出exceptions模块内容:

>>> import exceptions
>>> dir(exceptions)
['ArithmeticError', 'AssertionError', ...]

下面是使用内建异常类的简单例子:

>>> raise Exception
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Exception
>>> raise Exception('hyperdriver overload')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Exception: hyperdriver overload
8.2.2 自定义异常类

如果内建异常类不能满足程序的需求,可以自定义异常类。只需要保证自定义异常类是直接或者间接从Exception类继承的即可:

class SomeCustomException(Expception): pass

8.3 捕捉异常

假如有一个要让用户输入两个数来整除的程序是这样的:

n = input('Enter your first number:')
m = input('Enter your second number:')
print n / m


$ python class.py
Enter your first number:10
Enter your second number:0
Traceback (most recent call last):
  File "class.py", line 3, in <module>
    print n / m
ZeroDivisionError: integer division or modulo by zero

可以通过捕捉异常来处理它们:

try:
    n = input('Enter your first number:')
    m = input('Enter your second number:')
    print n / m
except ZeroDivisionError:
    print 'The second number can not be zero!'

$ python class.py
Enter your first number:10
Enter your second number:0
The second number can not be zero!

我们虽然捕捉了异常并打印了信息,实际上却可以不处理它,而让它继续传递。

如下是一个有 "屏蔽" ZeroDivisionError错误的代码示例。当muffled=Fasle时,会直接打印错误信息;否则异常会传递给上层调用者。


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
>>> c = MuffledCalculator()
>>> c.calc("12/0")

Traceback (most recent call last):
  File "class.py", line 12, in <module>
    c.calc("12/0")
  File "class.py", line 5, in calc
    return eval(expr)
  File "<string>", line 1, in <module>
>>> c.muffled = true
>>> c.calc("12/0")
ZeroDivisionError: integer division or modulo by zero

8.4 不止一个except子句

在前面的例子中,还会有别情况,比如用户输入的如果是字符串,直接进行除法运算可能导致TypeError的异常,这时候就可以用多个except子句:

try:
    n = input('Enter your first number:')
    m = input('Enter your second number:')
    print n / m
except ZeroDivisionError:
    print 'The second number can not be zero!'
except TypeError:
    print 'That was not number, is it?'

8.5 用一个块捕捉两个异常

上节中的多种异常情况如果不需要进行单独处理,能够更加简洁地用元组表示:

try:
    n = input('Enter your first number:')
    m = input('Enter your second number:')
    print n / m
except (ZeroDivisionError, TypeError, NameError):
    print 'Your number was bongus!'

当然只是打印错误信息并没有什么意义,另一个方案就是要求用户输入合理的数字直到可以进行运算位为止。

8.6 捕捉对象

如果不想终止程序运行,又想在except子句中获取错误信息,可以直接访问异常对象:

try:
    n = input('Enter your first number:')
    m = input('Enter your second number:')
    print n / m
except (ZeroDivisionError, TypeError, NameError), e:
    print e

$ python class.py
Enter your first number:10
Enter your second number:0
integer division or modulo by zero

8.7 真正的全捕捉

总有一些用户操作会躲过try/except的检查,比如在上面的例子中,用户什么也不输入直接回车:

$ python class.py
Enter your first number:
Traceback (most recent call last):
  File "class.py", line 2, in <module>
    n = input('Enter your first number:')
  File "<string>", line 0
    
    ^
SyntaxError: unexpected EOF while parsing

要Python对所有异常全部进行捕捉可以在except的子句中什么异常类也不写:

try:
    n = input('Enter your first number:')
    m = input('Enter your second number:')
    print n / m
except:
    print 'Something wrong happen...'

8.8 万事大吉

在try/except子句中,如果发生了exception会走except分支,如果没有发生exception,还可以新增一个else分支。如下示例:

try:
    print 'A Simple Task'
except:
    print 'What? Something went wrong!'
else:
    print 'Ah... I went as planed'

$ python class.py
A Simple Task
Ah... I went as planed

8.9 最后

除了else子句外,还有finally子句可以用来做一些清理工作(finally子句无论是否发生异常都会执行):

try:
    1/o
except NameError:
    print 'Unknown variable!'
else:
    print 'That wents well'
finally:
    print 'Clean up'
$ python class.py
Unknown variable!
Clean up

8.10 异常和函数

如果异常在函数中没有被处理,就会被传播至函数调用的地方,如此层层往上直到被处理。

8.11 异常之禅

在某些时候try/except和if/else子句可以实现同样的功能,但是if/else自然性和可读性差些,应该养成尽可能的多使用try/except的习惯。

“在做一件事情的过程中去处理可能出现的错误,而不是在做这件事情之前做大量的检查”。

8.12 小结

  • 异常对象
  • 警告[注:该章压根就没提到警告好么]
  • 引发异常
  • 自定义异常类
  • 捕捉异常
  • else子句
  • 异常和函数
8.12.1 本章的新函数

8.12.2 接下来学习什么


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

推荐阅读更多精彩内容