Python 极简教程(二十三) - 异常处理

异常,什么是异常呢?

有没有见过在浏览网页出现 500 错误?!

500错误

图片来自百度,侵删!

如果没见过,那肯定在学习 Python 过程中见过如下情景:


异常

不管是浏览网页时出现的 500 错误,还是在写代码过程中的 “报红”,这些都是代码在运行过程中出现了异常。

这些错误如果不处理会出现什么样的情况呢?当前运行的代码会中断。

print('start')
print(name)   # 注意,这里的 name 没有引号
print('end')

上图中的 name 没有打引号,会被 Python 认为是一个变量,而如果这个变量没有定义,那么会出现下面的错误:

错误

我们可以看到 start成功的打印了出来,但是 end却没有,这是因为 第二句print(name)抛出了异常。

那么会有什么影响呢?假如,我们是在操作文件或数据库的过程中出现了异常:

# 伪代码,只是为了说明操作文件和数据库的过程
# 操作文件过程
f = open('nemo.txt') # 打开文件
f.read()   # 读取文件内容
f.close()  # 关闭文件

# 操作数据库过程
db = connect()  # 连接数据库
db.options  # 数据库操作过程
db.close()  # 断开数连接

如果在这样的处理过程中,操作文件的过程或者操作数据库的过程中报错了,会导致后续的文件关闭和数据库连接无法正常断开。这就会造成内存驻留和数据库的连接被占用。

通常,为了保证关闭操作能够正常进行,我们都需要处理操作过程中可能出现的异常。当然还有很多其他的用处!

在 Python 中,处理异常的语句为try...except...finally(else)...

具体语法如下:

try:
  可能出现异常的语句块

except 错误类型:
  如果出现错误后,执行的代码

else:
  没有出现错误,执行这里的代码

finally:
  不管有没有出现错误,这里的代码都会执行

举例来说。假设我们现在想写一个函数,用来进行出发运算,但是除数不能为0,为0就会报一个异常ZeroDivisionError,当用户不小心把被除数数为0,我们不能直接给用户一个异常扔脸上吧!所以我们至少要处理一下异常,并告诉用户你输错了。

def division(a, b):
  '''a 为被除数,b 为除数'''
  try:
    return a/b
  except ZeroDivisionError:
    print('除数不能为 0 !')

>>> division(10,2)
5.0
>>> division(5,0)
除数不能为 0 !

但是用户除了可能会乱输 0 以外,还可能输一些命名其妙的符号。

>>> division(10,'$@]')
...异常堆栈信息省略
TypeError: unsupported operand type(s) for /: 'int' and 'str'

咦,不是做了异常处理么?咋还要报错呢?

这回错误不一样了,是TypeError

回头看看我们写的函数,我们只处理了ZeroDivisionError这种异常,而对于非数字类型的错误没有处理。那要处理怎么办呢?

针对上面报的TypeError ,再加一个 except 处理:

def division(a, b):
  '''a 为除数,b 为被除数'''
  try:
    return a/b
  except ZeroDivisionError:
    print('被除数不能为 0 !')
  except TypeError:
    print('除法只支持数值类型!')

>>> division(10,'$@]')
除法只支持数值类型!

好了,这种异常也处理了。可能有人会问,有没有能一次性处理所有异常的方式呢?

当然有,就是使用所有异常类型(每种异常类型是 Python 中的一个异常类)的父类Exception

def division(a, b):
  '''a 为被除数,b 为除数'''
  try:
    return a/b
  except Exception:
    print('你的输入有误!')

>>> division(10,'$@]')
你的输入有误!
>>> division(5,0)
你的输入有误!

我们会发现,虽然这种方式能处理所有异常,但是没有办法针对不同的情况给予用户合适的提示。所以根据情况选用!

接下来,我们说一下finallyelse子句。

先说 else,我们改造一下除法函数,当输入正确的情况下,我们告诉用户除法的结果。

def division(a, b):
  '''a 为被除数,b 为除数'''
  try:
    r = a/b
  except ZeroDivisionError:
    print('除数不能为 0 !')
  except TypeError:
    print('除法只支持数值类型!')
  else:
    print(f'{a} 除以 {b} 的结果是 {r}')

>>> division(10,'$@]')
除法只支持数值类型!
>>> division(10, 2)
10 除以 2 的结果是 5.0

在某些情况下,可以使用 try...except...else...代替if...else...来使用。

最后就是 finally 子句了,finally 是无论如何都会执行的。我们看下面的例子

a = input('请输入一个数:')
try:
    a = int(a)
    b = 100 / a
except ValueError:
    print('请输入整数!')
print('end')

当某种异常没有被捕获到的时候,我们发现后面的 print('end')并没有执行。如果我们想无论如何都执行 print('end'),就可以使用 finally。

a = input('请输入一个数:')
try:
    a = int(a)
    b = 100 / a
except ValueError:
    print('请输入整数!')
finally:
    print('end')

请输入一个数:0
end
...异常堆栈省略
ZeroDivisionError: division by zero

我们可以看到 end 也会打印出来,异常也会抛出来。

那么对于文件操作就可以将 close() 关闭语句放在 finally 中,以保证无论什么情况下文件都能被正常关闭。

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

推荐阅读更多精彩内容