和其他语言一样,Python中的异常处理是很重要的机制和代码规范。

一.错误与异常

  通常来说程序中的错误分为两种,一种是语法错误,另一种是异常。首先要了解错误和异常的区别和联系。

  语法错误比较容易理解,就是写的代码不符合变成规范,无法被识别或执行,就像这样

>>> print(name)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'name' is not defined

由于name这个变量在被调用前没有被声明,在被调用时就会报错。或者if语句后遗漏了冒号、缩进错误等等。

  而异常则是指程序可以正常执行,但是在执行过程会遇到错误然后抛出异常,比如这样

>>> l = [1,2,3]
>>> l + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "int") to list
>>> 10/0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> dic = {'name':''}
>>> dic['age']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'age'

上面的例子中出现了三种异常,分别是类型错误、除数不能为0和字典键错误。异常种类还有很多很多中,其他的可以查询异常的官方文档

二.异常的处理

  如果程序在执行中某处跑到了异常,程序就会终止并退出,而有些时候我们是不想让程序停止的,这时候就要用到异常处理了,通常使用try和except来实现。比如这样:

while True:
a = input('a:')
b = input('b:')
try:
a = float(a)
b = float(b)
print('a/b={}'.format(a/b))
except ZeroDivisionError as e:
print(e)

  这样当输入的b值为0时,程序就会抛出异常并打印出来

a:1
b:0
float division by zero

  但是,except block只能catch和列出来的异常匹配的异常类型,当输入的a或b是非数字字符串时,还是会报错后程序终止并退出。

a:a
b:2
Traceback (most recent call last):
File "D:/python/Python核心技术实战/异常处理.py", line 6, in <module>
a = float(a)
ValueError: could not convert string to float: 'a'

  解决方法有两种,一种就是把可能会出现等待异常就要把两种异常都列出来,比如这样

while True:
a = input('a:')
b = input('b:')
try:
a = float(a)
b = float(b)
print('a/b={}'.format(a/b))
except (ZeroDivisionError,ValueError) as err:
print(err)

  或者分开来写

while True:
a = input('a:')
b = input('b:')
try:
a = float(a)
b = float(b)
print('a/b={}'.format(a/b))
except ZeroDivisionError as err:
print('ZeroDivisionError:{}'.format(err))
except ValueError as err:
print('ValueError:{}'.format(err))

  这样,在程序执行的时候,except block中只要有一个exception类型与之实际匹配就可以。

  不过在大多数时候我们很难保证程序能覆盖所有的异常类型,所以通常的做法实在最后加一个except block,声明的异常类型时Exception。Exception是所有非系统异常的基类,能够匹配所有非胸痛异常。所以代码应该是这样的

while True:
a = input('a:')
b = input('b:')
try:
a = float(a)
b = float(b)
print('a/b={}'.format(a/b))
except ZeroDivisionError as err:
print('ZeroDivisionError:{}'.format(err))
except ValueError as err:
print('ValueError:{}'.format(err))
except Exception as err:
print('Other error:{}'.format(err))

  或者在except后面省略异常类型,表示与任意异常匹配(包括系统异常)。

except:
print('Other error')

  这里有个点要注意一下:如果程序中存在多个except block时,最多只能由一个block被catch,,也就是说只有最前面的那个block会执行,后面的就被忽略了。

三.finally的用法

  在异常处理中还有一个最常用的方法是finally,它经常和try、except一起使用,无论前面发生什么情况,finally block中的语句都会执行。即便前面的block中由return。一个常见的场景就是对文件的读取操作

try:
f = open('file.txt','r')
except OSError as err:
print(err)
except:
print('Unexpected error')
finally:
f.close()

不管前面执行了什么操作,最后都是要关闭文件,从而确保文件的完整性。所以,在finally中,我们会放置一些无论如何都要执行的语句。其实针对上面这个对文件进行操作的例子,在前面的用法是用with open语法,在with open最后会自动关闭文件使代码看起来更整洁。

四.用户自定义异常

  上面的例子里已经列举了几种Python内置的异常类型,还给出了官方的文档。其实我们还可以自己定义异常类型

class MyInputError(Exception):
def __init__(self,value):
self.value = value
def __str__(self): #自定义异常的string表达式
return ('{} is invalid input'.format(repr(self.value)))
try:
raise MyInputError(123) #直接抛出异常
except MyInputError as err:
print('error:{}'.format(err))

  这里我们还用了raise来直接抛出异常。其实Python的内置异常种类通常来说已经够用了!正常情况不需要用户自己定义!

五.异常的使用场景与注意点

  这一段里我们要着重来看一下异常的使用场景和注意点:

  通常来说,如果我们不确定某段代码能否成功执行,往往这里就需要加上异常处理比如我们从database里获取了一个key-value结构的数据,在一般的网站后台这种数据都是经过json序列化后的字符串,我们要想获得数据就需要将字符串decode。

import json
raw_data = queryDB(uid) #获取json序列化后的字符串数据
data = json.loads(raw_data)

  在json.loads()函数中如果输入的字符串不符合其规范,就无法解码,程序会抛出异常,这个时候加上异常处理就显得非常重要。

  但是我们还要避免走向另一个极端:滥用异常处理

data = {'name':'jack',
'age':22}
try:
data['job'] except KeyError as err:
print('KeyError:{}'.format(err))

  这样的代码其实是没问题的,但是显得有冗余,一般是没有人这么用的。直接这样用就可以了

if 'job' in data:
data['job']

  更简单的,直接这样写

data.get('job')

  所以,一般的flow-control(流程控制)的代码逻辑,我们一般是不用异常处理的

Python核心技术与实战——六|异常处理的更多相关文章

  1. Python核心技术与实战——十九|一起看看Python全局解释器锁GIL

    我们在前面的几节课里讲了Python的并发编程的特性,也了解了多线程编程.事实上,Python的多线程有一个非常重要的话题——GIL(Global Interpreter Lock).我们今天就来讲一 ...

  2. Python核心技术与实战——十六|Python协程

    我们在上一章将生成器的时候最后写了,在Python2中生成器还扮演了一个重要的角色——实现Python的协程.那什么是协程呢? 协程 协程是实现并发编程的一种方式.提到并发,肯很多人都会想到多线程/多 ...

  3. Python核心技术与实战 笔记

    基础篇 Jupyter Notebook 优点 整合所有的资源 交互性编程体验 零成本重现结果 实践站点 Jupyter 官方 Google Research 提供的 Colab 环境 安装 运行 列 ...

  4. Python核心技术与实战——二一|巧用上下文管理器和with语句精简代码

    我们在Python中对于with的语句应该是不陌生的,特别是在文件的输入输出操作中,那在具体的使用过程中,是有什么引伸的含义呢?与之密切相关的上下文管理器(context manager)又是什么呢? ...

  5. Python核心技术与实战——二十|assert的合理利用

    我们平时在看代码的时候,或多或少会看到过assert的存在,并且在有些code review也可以通过增加assert来使代码更加健壮.但是即便如此,assert还是很容易被人忽略,可是这个很不起眼的 ...

  6. Python核心技术与实战——十八|Python并发编程之Asyncio

    我们在上一章学习了Python并发编程的一种实现方法——多线程.今天,我们趁热打铁,看看Python并发编程的另一种实现方式——Asyncio.和前面协程的那章不太一样,这节课我们更加注重原理的理解. ...

  7. Python核心技术与实战——四|Python黑箱:输入与输出

    抽象的看,Python程序可以被看成一个黑箱:通过输入流将数据送达,经过处理后在输入,也就是说具备了一个图灵机运作的必要条件. 输入输出基础 最简单的输入是来自键盘的操作 name = input(' ...

  8. Python核心技术与实战——二十|Python的垃圾回收机制

    今天要讲的是Python的垃圾回收机制 众所周知,我们现在的计算机都是图灵架构.图灵架构的本质,就是一条无限长的纸带,对应着我们的存储器.随着寄存器.异失性存储器(内存)和永久性存储器(硬盘)的出现, ...

  9. Python核心技术与实战——十七|Python并发编程之Futures

    不论是哪一种语言,并发编程都是一项非常重要的技巧.比如我们上一章用的爬虫,就被广泛用在工业的各个领域.我们每天在各个网站.App上获取的新闻信息,很大一部分都是通过并发编程版本的爬虫获得的. 正确并合 ...

随机推荐

  1. SRCNN 卷积神经网络

    2019-05-19 从GitHub下载了代码(这里) 代码量虽然不多,但是第一次学,花了时间还是挺多的.根据代码有跑出结果(基本没有改),但是对于数据集的处理还是看的很懵逼,主要是作者的实现都是用类 ...

  2. P1309 瑞士轮 (吸氧了)

    P1309 瑞士轮 题解 1.这题可以模拟一下 2.sort吸氧可以过(可能是排序有点慢吧,不开会T) sort排序时注意: return 1 是满足条件,不交换 return 0是不满足,交换 代码 ...

  3. 2、Shiro的认证

    Shiro的认证流程大体可以参考下面这幅图: 但是没有接触过shiro的同学看到上面的图片也不明白,下面我们来在代码中尝试体验Shiro的认证过程: 1.新建一个SpringBoot项目项目结构如下: ...

  4. python - Tkinter 模块 - python 自带的gui模块

    Tkinter模块("Tk 接口")是Python的标准Tk GUI工具包的接口,位Python的内置模块,直接import tkinter即可使用. 1.创建窗口 from Tk ...

  5. JS数组方法的的返回值和是否改变该数组总结

    concat() 方法 concat() 方法用于连接两个或多个数组. 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本. 返回值 返回一个新的数组.该数组是通过把所有 arrayX 参数添 ...

  6. 2.k8s.Pod生命周期,健康检查

    #Pod生命周期,健康检查 pod创建过程 Init容器 就绪探测 存活探测 生命周期钩子 #Pod创建过程 master节点:kubectl -> kube-api -> kubenle ...

  7. 用户tokenId

    tokenId表示为:用户登录到成功后,服务端分配给客户端的令牌号,同时下发tokenId的过期时间.下次用户直接持有tokenId,在其过期时间内均可跳过用户登录步骤,直接请求其他服务操作.如果to ...

  8. SIRIM上海,http://www.sirim-global.com

    SIRIM上海 http://www.sirim-global.com

  9. [19/05/28-星期二] JavaScript_ 对象和引用数据类型

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. MySQL-快速入门(4)MySQL函数

    1.函数包括:数学函数.字符串函数.日期和时间函数.条件判断函数.系统信息函数.加密函数. 2.数学函数:绝对值函数.三角函数(正弦函数.余弦函数.正切函数.余切函数等).对数函数.随机数函数. 1& ...