编程入门12:Python异常处理

上一篇:编程入门11:Python面向对象

我们在编程时常常要和各种错误信息打交道,当Python解释器发现程序的错误时,就会抛出“异常”(Exception)来提示错误——这种情况可能发生于“编译时”和“运行时”这两个不同的阶段:Python程序在运行之前要先编译,如果编译未通过就不会开始运行——你可以在IPython一次交互中输入包含多条语句的程序来验证一下(按Ctrl+Enter换行,按Shift+Enter提交):

In [1]: print(2/3)
   ...: print(2///3)
   ...: print("结束")
  File "<ipython-input-1-90ecc1ce7c0b>", line 2
    print(2///3)
             ^
SyntaxError: invalid syntax


In [2]: print(2/3)
   ...: print(2/0)
   ...: print("结束")
   ...: 
0.6666666666666666
Traceback (most recent call last):

  File "<ipython-input-2-7d58b37c849b>", line 2, in <module>
    print(2/0)

ZeroDivisionError: division by zero

上面第一段程序的第二句不符合语法,编译因此中断并抛出“语法错误”(SyntaxError)异常,这就属于编译时错误;通过编译的程序在运行期间仍可能出现导致程序中止的问题——上面第二段程序在语法上没有问题,第一句也正常执行了,但第二句中除数为零的运算违反数学规则,运行因此中止并抛出“除零错误”(ZeroDivisionError)异常,这就属于运行时错误。

运行时错误难免会发生——用户输入的数据不完整、打开的文件格式不正确或连接的网络不通畅等等,都可能导致抛出异常。开发者应该预先考虑到各种异常情况,增加相应的代码来处理运行时错误以避免程序意外中止。所有异常对象都是特定异常类的实例,最基本的异常类是BaseException,通常在编程中需要处理的异常则都继承自BaseException的子类Exception。如果想要查看异常类的继承关系,可以使用mro方法返回“方法解析顺序”(Method Resolution Order)——这实际上就是类的继承顺序,一直上溯到object类为止。此外,你还可以使用raise语句直接“召唤”异常,或使用assert语句“指明”条件来触发异常。

In [3]: SyntaxError.mro()
Out[3]: [SyntaxError, Exception, BaseException, object]

In [4]: ZeroDivisionError.mro()
Out[4]: [ZeroDivisionError, ArithmeticError, Exception, BaseException, object]

In [5]: help(Exception.mro)
Help on built-in function mro:

mro(...) method of builtins.type instance
    mro() -> list
    return a type's method resolution order

In [6]: raise Exception("发生了错误")
Traceback (most recent call last):

  File "<ipython-input-6-2b67d8d306dd>", line 1, in <module>
    raise Exception("发生了错误")

Exception: 发生了错误

In [7]: a = 20
   ...: assert a <= 10, "数值过大"
   ...: 
Traceback (most recent call last):

  File "<ipython-input-7-58c21e2f5947>", line 2, in <module>
    assert a <= 10, "数值过大"

AssertionError: 数值过大

Python提供try语句来实现异常处理:“尝试”执行可能出错的代码,如有“异常”就进行相应处理——提醒用户再次输入、检查文件或重新连网等等,使程序能够顺畅地运行下去。下面我们来看一个非常简单的计算程序:根据输入的算式输出答案——使用eval函数能把字符串作为表达式来求值,但是用户可能输入不合法的表达式,导致运行时错误的发生,因此就要使用try语句来处理异常:尝试运行try代码段,如无异常则运行之后的语句,如有异常就转而执行except代码段,这样即使用户输入错误的内容,程序也不至于崩溃。

"""calc.py 简单的计算程序
"""
ans = ""
while True:
    ask = input("输入算式或回车退出:")
    if ask == "":
        break
    try:
        ans = eval(ask)
    except:
        pass
    print(ans)

以上程序中的pass语句表示什么也不做直接放过,这当然不好——正如Python之禅所言“错误不可放过”——以下程序捕获抛出的Exception类(包括其所有继承者)实例并赋值给变量e,这样就能用repr(e)返回异常类型及提示信息,通知我们具体发生了什么问题再继续运行:

    except Exception as e:
        ans = repr(e)

你可以在try语句中使用多个except子句,捕获不同类型的异常进行分别处理,例如输出自定义的提示信息。此外,你还可以添加一个finally子句,在其中编写无论是否发生异常都要“最终”执行的代码。

    except SyntaxError:
        ans = "语法不正确"
    except ZeroDivisionError:
        ans = "除数不能为零"
    except Exception as e:
        ans = "发生{}错误".format(e.__class__.__name__)
    finally:
        print("输出结果:", end="")

下面让我们来看一个在线随机图片API的测试程序:访问指定的“岁月小筑”网址会返回一张随机图片的网址,然后调用默认浏览器打开:

"""urlgetpic.py “岁月小筑”随机图片API测试程序
获取一张随机图片的网址并用浏览器打开
"""
from urllib.request import urlopen
import webbrowser
url = "http://img.xjh.me/random_img.php?return=url"


def main():
    try:
        pic = urlopen(url).read().decode()
        webbrowser.open("http:" + pic)
    except Exception as e:
        print(repr(e))


if __name__ == "__main__":
    main()
12_pic.jpg

网络总会有连不上的时候,所以访问在线资源的代码应该用try语句加以保护。

——编程原来这样……

编程小提示:开放API

API指“应用编程接口”(Application Programming Interface),其作用是让外部开发者可以调用程序的特定功能,而又无需关心程序内部的细节。在互联网时代,把网络服务封装成一系列数据接口开放出去供第三方开发者使用,这就叫做开放API——从更广泛的意义上讲,任何网站都是API,你可以编写程序从网站中获取所需要的信息,就像调用本地函数返回结果一样。

下一篇:编程入门13:Python文本处理

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

推荐阅读更多精彩内容

  • 引言 在程序运行过程中(注意是运行阶段,程序可以通过编译),如果JVM检测出一个不可能执行的操作,就会出现运行时错...
    Steven1997阅读 2,392评论 1 6
  • Python 面向对象Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对...
    顺毛阅读 4,207评论 4 16
  • 八、深入理解java异常处理机制 引子try…catch…finally恐怕是大家再熟悉不过的语句了, 你的答案是...
    壹点零阅读 1,526评论 0 0
  • 有人说年轻是资本,充沛的时间和精力,打一打鸡血就能向前猛冲。也有人说,年轻就是一张白纸,什么都不是,唯有等在染缸里...
    梦鱿者阅读 4,220评论 1 8
  • 不知道第几天冥想了,观想顶轮的时候会看到自己的顶轮不再是一个圆圈什么的,而是一个皇冠,皇冠下面部分是原子运行的轨迹...
    米粒粒1阅读 208评论 2 0