python异常处理结构_Python 基本功: 8. 异常处理

相信大家在跟随教程到现在,已经遇到过 Python 不同数量的报错了。但是遇到报错不需要害怕,因为我们有句话说:能够报错的就不是错,真正的错是不会自己报错的。

今天我们就来讲一下该如何做异常处理,首先需要完成教程:多多教Python:Python 基本功: 6. 第一个完整的程序​zhuanlan.zhihu.comv2-6c4fc56914acd34bf7f675ce5e094691_180x120.jpg多多教Python:Python 基本功: 7. 介绍函数​zhuanlan.zhihu.comv2-154623bd56e285b07711b685f615f24f_180x120.jpg

并且已经成功运行了教程里介绍的完整的程序。

教程需求:Mac OS (Windows, Linux 会略有不同)

安装了 Python 3.0 版本以上, PyCharm

异常 Exception

当 Python 程序遇到无法执行的命令的时候,就会把无法执行的命令和一堆内存里的数据给反馈出来,这时候程序就停止了,并且留下了一堆代码信息,有点像 Windows 时代的蓝屏。我们都知道用 Windows 最讨厌的就是蓝屏死机,好在 Python 是一门设计巧妙的语言,我们可以通过异常处理的语法来避免程序死机报错,让我们的程序哪怕遇到问题了仍然能正常的运行下去。

现在我们来看一下 Python 中异常处理的语法:

try:

# do something

except Exception as error:

# error handling

finally:

# optional, clean uptry: 这里开始进入抓去异常的范围。

# do something: 运行你写的代码。

except ...: 到这里异常抓取范围结束,在这个范围内如果发生指定的异常事件,就会被“抓住”处理。

Exception as error: 这里指定的异常事件是 Exception 类,抓住了之后给其定义一个变量叫 error, 然后进入异常处理。

# error handling: 这里是抓住了异常事件之后做处理。

finally: 这是可有可无的,不论异常有没有出现被抓住,都会进入这个语法,一般是用来做数据清理,并且保证可以被执行的一段话。

Python的异常处理语法是非常简单的,具体如何使用可能大家还不是很明白,没关系,在之后的实际操作中可以慢慢体会。我们先从比较高层次来了解 Python 异常的种类,来看看 Python 到底可以抛出哪些异常类型:

+-- BaseException (new; broader inheritance for subclasses)

+-- Exception

+-- GeneratorExit (defined in PEP 342 [1])

+-- StandardError

+-- ArithmeticError

+-- DivideByZeroError

+-- FloatingPointError

+-- OverflowError

+-- AssertionError

+-- AttributeError

+-- EnvironmentError

+-- IOError

+-- EOFError

+-- OSError

+-- ImportError

+-- LookupError

+-- IndexError

+-- KeyError

+-- MemoryError

+-- NameError

+-- UnboundLocalError

+-- NotImplementedError (stricter inheritance)

+-- SyntaxError

+-- IndentationError

+-- TabError

+-- TypeError

+-- RuntimeError

+-- UnicodeError

+-- UnicodeDecodeError

+-- UnicodeEncodeError

+-- UnicodeTranslateError

+-- ValueError

+-- ReferenceError

+-- StopIteration

+-- SystemError

+-- Warning

+-- DeprecationWarning

+-- FutureWarning

+-- PendingDeprecationWarning

+-- RuntimeWarning

+-- SyntaxWarning

+-- UserWarning

+ -- WindowsError

+-- KeyboardInterrupt (stricter inheritance)

+-- SystemExit (stricter inheritance)

这个列表是 Python 全部的异常类型,直接从 Python 3.8 官网上面拷贝下来的,虽然我不是很喜欢直接从别的地方拷贝引用,但是异常的种类还是很需要记忆下来的。其实你一旦熟悉了异常种类,在之后的程序设计,运行中就可以少走很多弯路,避免很多坑。

因为这是一个父子的结构,最高级的 BaseException 是一个虚拟类,我们之后会讲到什么是虚拟类。随后的三大类分别是:Exception: 这一类就是在上面例子用到的,包括了软件里几乎会出现的所有错误:计算错误,环境错误,内存错误,类型错误,运行错误,网络错误等等。

KeyboardInterrupt: 这一类错误是 Python 程序收到非正常操作系统的指令时发出的。情况在 多多教Python:Python 基本功: 1. Hello world 中提到的用 cntrl+Z 来打断退出程序。

SystemExit: 这类错误一般是操作系统直接关闭程序时发出的,情况包括程序里面有恶意代码被操作系统发现,直接关停。

注意,如果你在 except... 语句中特地抓去的是内存错误,那么当发生网络类型的错误的时候,就不会进入错误被抓去的语句中。但是如果你抓取的是这个类型的上一级,父类,则其子类报错的时候都会被抓住。

异常处理 Exception Handling

既然介绍了语法,那么我们来看看如何正确的处理一些异常。现在回到多多教Python:Python 基本功: 7. 介绍函数 里的例子,这里我们的程序可以正常的运行,但是没有任何异常处理代码,如果发生了意外情况程序就会直接关停,那我们来做一个最简单的操作:

if __name__ == '__main__':

# 报告文件名

if len(sys.argv) > 1:

report_date = sys.argv[1]

else:

report_date = ""

abc_file = 'abc_date_price.txt'

try:

abc_dict = report_daily_price(ticker='ABC', input_file=abc_file, report_date=report_date)

except Exception as err:

print(err)

abc_dict = {}

finally:

print(abc_dict)

在 main() 方法里调用函数 report_daily_price 的时候,我们加上了异常处理,抓去 Exception 或者其子类的异常,如果抓取到了则打印出异常,并且设立一个空的字典。最后不论抓取到异常与否,都打印出字典。这里如果函数报错,则函数就不会有回复,所以在抓取到错误的时候要重新建立一个字典,这样可以在 finally... 语句中打印出来。

这么做的好处是如果函数报错,你可以抓住错误并且直接在程序内部处理掉,否则程序就会退出,并且报错的语句也有可能丢失。

接下来我们进入函数,在函数里做一些更加细致的异常处理:

try:

with open(report_file, 'r') as file_to_write:

json.dump(output_dict, file_to_write)

except IOError as io_error:

print("IO error caught: " + str(io_error))

在函数最后把字典以 Json 格式写入文件时候,我们加上异常处理,并且把 open() 里的格式参数从 'w' 改成 'r',在 多多教Python:Python 基本功: 4. 读写文件 已经讲过了,'w' 代表可以写入,‘r’ 代表了只能读取,所以我们这里打开了一个只读文件尝试写入,看看会发生什么情况:

IO error caught: not writable

不出意料,我们抓住了这个异常,是一个 I/O 错误类,I/O 代表了数据的读写通道错误,一般会出现在保存在硬盘的文件读写上。并且错误语句也很明显,“not writable” 就是无法写入的意思。

下面我们再来举一个例子:

try:

ret_pcnt = (ret_dict[datetime(2019, 8, 18)] - ret_dict[datetime(2019, 7, 10)]) / ret_dict[datetime(2019, 7, 18)]

except KeyError as key_error:

print("Key error caught: " + str(key_error))

ret_pcnt = 0

这里在计算回报率的时候,加上了 KeyError, 钥匙错误的抓取。KeyError 在字典查询的时候非常常见,而这里我们故意把一个日期 datetime(2019, 7, 19) 尝改成一个字典中不存在的钥匙 datetime(2019, 8, 19),然后运行。不出所料,我们抓住了这个错误,并且报错是:

Key error caught: datetime.datetime(2019, 8, 18, 0, 0)

KeyError 报错会同时把这个 Key 的数值给报错出来,告诉你是这个 Key 出现了错误,还是很人性化的。

上报错误 Raise Exception

有的时候你知道这个地方有可能会出现异常,但是不想在这个函数里解决这个异常,就交给函数外部处理,甚至你可以主动的扔出一个异常,通过语法 Raise:

try:

ret_pcnt = (ret_dict[datetime(2019, 8, 18)] - ret_dict[datetime(2019, 7, 10)]) / ret_dict[datetime(2019, 7, 18)]

except KeyError as key_error:

print("Key error caught: " + str(key_error))

ret_pcnt = 0

if ret_pcnt == 0:

raise ZeroDivisionError("Return pcnt should not be 0, check calculation")

紧接着第一个 try...except... 语句,我们加上了如果回报率是0,则扔出 ZeroDivisionError, 并且附带一句话请检查计算。这里扔出的 ZeroDivisionError 是指数据处以0后会无限大的错误。这是一个预防性的上报错误,以防之后当遇到除以 回报率的计算的时候出现 ZeroDivisionError。在这里就举一个例子,之后会教你自己根据需求创建一个错误类。

运行程序,我们会发现函数会进入 raise... 语句,扔出 ZeroDivisionError, 然后函数就结束了。随后在函数外部,main() 方法下这个异常被抓住,并且异常的语句,也就是我们写的检查计算语句,被打印出来。

小结:

异常处理对于一个强壮的程序很重要。如果你想写一个 Python 机器人不经常掉线,或者蓝屏的,你需要知道里面每一行代码有可能出现什么错误,并且用正确的错误类型抓住。当然在基础篇我们如果能做到在可能出错的地方用最基本的 Exception 抓取,然后把错误打印出来,就已经很到位了。接下来加上两个链接有兴趣的小伙伴可以去看看:

一个外部的异常处理教程:Python 异常处理 | 菜鸟教程​www.runoob.com

Python 3.8 官方异常结构:PEP 348 -- Exception Reorganization for Python 3.0​www.python.orgv2-ff06c339780f23112c1cbbbb284158ff_ipico.jpg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值