1. 异常
1.1 try...except
又到了开新课的时候了, 小明同学这次提前预习了知识, 乘着老师还没来就在黑板上写下了这段 Code:
- In [1]:
- def main():
- try:
- 1 / 0 # ZeroDivisionError: division by zero
- except ZeroDivisionError as ex:
- print(ex)
- if __name__ == '__main__':
- main()
- division by zero
- 1.2 try...except...else...finally
小潘同学刚进来就看见了, 自语道:"try...except 捕获异常谁不会? 就会这么屁点东西还好意思秀, 切~ 我给你把 格式补全"
于是乘着小明上厕所的时候, 擦掉小明的 Code, 自己写了一段高大上的 Code:
- In [2]:
- # 异常捕获全格式
- def test(input_str):
- try:
- eval(input_str)
- except ZeroDivisionError as ex:
- print("except:", ex)
- else:
- print("else: 没有异常就奖励 100 块~")
- finally:
- print("finally: 小明是傻子~")
- def main():
- test("1/0")
- print("-" * 10)
- test("print('小明啊小明你调坑里了~')")
- if __name__ == '__main__':
- main()
- except: division by zero
- finally: 小明是傻子~
- ----------
- 小明啊小明你调坑里了~
- else: 没有异常就奖励 100 块~
- finally: 小明是傻子~
这时候小明和老师一起进来了, 同学们隐约间都听到小明的自夸声:"老师, 我可好了, 提前预习并且还写了个 demo 在黑板上呢~"
老师一进门看着黑板就笑了, 同学们也笑成一片. 小明心想, 咦~难道我写错了? 定眼一看黑板, 气呼呼的回座位了
else 可以不写, 不过我们 基本上还是会写的, 毕竟可以知道是真的没有错误, 而不是屏蔽了错误
1.3 多个异常处理
老师很欣慰, 觉得这个班真有意思, 大家学习空前热情, 为了照顾小明, 老师反问道:"有谁知道 多个异常怎么处理?"
小明飞快的举手并把黑板上内容擦完, 写下了如下代码:
- In [3]:
- # 多个异常捕获
- def main():
- try:
- print(xiaopan) # NameError: name 'xiaopan' is not defined
- 1 / 0 # ZeroDivisionError: division by zero
- except NameError as ex:
- print(ex)
- except ZeroDivisionError as ex:
- print(ex)
- if __name__ == '__main__':
- main()
- name 'xiaopan' is not defined
老师问了小明一声, 有几个输出?
小明骄傲的说道:"两个, 我写了两个异常处理, 当然都执行了"
同学们又笑了, 小潘调侃的说了句:"一看就知道去年 C# 没好好学, 这不都一样嘛, 遇到异常下面代码还执行吗? 用脑子好好想想"
当我们认为某些代码可能会出错时, 就可以用 try 来运行这段代码, 如果执行出错, 则后续代码不会继续执行, 而是直接跳转至 except 语句块, 执行完 except 后, 如果有 finally 语句块, 则执行 finally 语句块
小明又尴尬了...
1.4 多异常简写
老师再次帮小明圆了个场:"已经很不简单了, 就是最后小得意的时候口误了, 那小明同学你知道 Python 里面多异常有个便捷写法吗?"
小明赶紧拿起粉笔刷刷刷的写完, 然后说道:"of course"
- In [4]:
- # 多个异常捕获的简写(注意哦, 是元组哦)
- def main():
- try:
- print(xiaopan) # NameError: name 'xiaopan' is not defined
- 1 / 0 # ZeroDivisionError: division by zero
- except (NameError, ZeroDivisionError) as ex:
- print(ex)
- if __name__ == '__main__':
- main()
- name 'xiaopan' is not defined
老师赶紧夸了夸小明, 心想, 哎呦喂终于把这难缠的家伙弄回座位了.
小明走前还不忘说一句:"简写的时候注意格式哦, 是 元组 不是逗号分隔"
老师这堂课很轻松, 大家都预习了而且内容也比较简单.
接着以提问的方式问道:"小潘同学, 你知道异常的基类是什么吗? 如果要捕获所有异常该怎么做呢?"
小潘站起来说道:"是 BaseException"
老师扩充道:"所有的错误类型都继承自 BaseException, 所以在使用 except 时需要注意的是, 它不但捕获该类型的错误, 还把其子类也一起捕获了"
所以一般在捕获异常的时候 把子类异常放在前面, 父类放在后面
看如下代码:
- In [5]:
- def main():
- try:
- 1 / 0 # ZeroDivisionError: division by zero
- except BaseException as ex:
- print("base:", ex)
- except ZeroDivisionError as ex:
- print(ex)
- if __name__ == '__main__':
- main()
- base: division by zero
如果把父类放第一个, 那么 ZeroDivisionError 永远也不会被执行了, 其实你如果装了 代码规范提示插件会提示你的
可以参考我之前写的 vscode 设置 python3 调试环境的扩充部分
来个通用异常捕获的简写(官方不推荐使用简写):
- In [6]:
- # 直接 except 就行了
- def main():
- try:
- 1 / 0
- dnt += 1
- except:
- print("屏蔽错误")
- if __name__ == '__main__':
- main()
屏蔽错误
老师继续讲到, 我们来看一个场景, 现在很多在线编辑器, 你在他们那些编辑框里写下了代码也是有异常抛出的, 这是怎么处理的呢?
微软有开源代码编辑器比较受欢迎(VSCode 的一部分): https://microsoft.github.io/monaco-editor
提示一下, 如果真的要做在线编辑器, 记得考虑一下 fork 炸弹, 这个其实也是很老的东西了, 程序员基本上都应该接触过了
1.5 抛出异常
我们继续, 像 C# 是用 thorw 抛出异常, 那 Python 怎么
捕获异常后再抛出
呢? 怎么自定义异常 呢?
继续往下看:
- In [7]:
- # 捕获异常后再丢出, eg: 在线运行的用户 Code
- def main():
- try:
- 1 / 0 # ZeroDivisionError: division by zero
- except ZeroDivisionError as ex:
- print(ex) # 写个日志, 回头出问题可以深究
- raise
- if __name__ == '__main__':
- main()
- division by zero
- ---------------------------------------------------------------------------
- ZeroDivisionError Traceback (most recent call last)
- <ipython-input-7-15f01346e2d8> in <module>()
- 9
- 10 if __name__ == '__main__':
- ---> 11main()
- <ipython-input-7-15f01346e2d8> in main()
- 2 def main():
- 3 try:
- ----> 41 / 0 # ZeroDivisionError: division by zero
- 5 except ZeroDivisionError as ex:
- 6 print(ex) # 写个日志, 回头出问题可以深究
- ZeroDivisionError: division by zero
- In [8]:
- # 抛出自定义异常
- class DntException(BaseException):
- pass
- def get_age(num):
- if num <= 0:
- raise DntException("num must>0")
- else:
- print(num)
- def main():
- get_age(-1)
- get_age(22) # 程序崩了, 这句话不会被执行了
- if __name__ == '__main__':
- main()
- ---------------------------------------------------------------------------
- DntException Traceback (most recent call last)
- <ipython-input-8-7c9dec6ec225> in <module>()
- 17
- 18 if __name__ == '__main__':
- ---> 19main()
- <ipython-input-8-7c9dec6ec225> in main()
- 12
- 13 def main():
- ---> 14get_age(-1)
- 15 get_age(22) # 程序崩了, 这句话不会被执行了
- 16
- <ipython-input-8-7c9dec6ec225> in get_age(num)
- 6 def get_age(num):
- 7 if num <= 0:
- ----> 8raise DntException("num must>0")
- 9 else:
- 10 print(num)
- DntException: num must>0
异常这一块基本上讲完了 (logging 模块后面会说) 有什么补充的可以说的 ^_^
1.6 C# 异常
小明又进行了 C# 的代码转换, 怎么看都觉得还是 C# 简单啊, 根本不用说啥, 代码一贴就秒懂了...
- In [1]:
- %%script csharp
- try
- {
- Convert.ToInt32("mmd");
- }
- catch (Exception ex)
- {
- // Input string was not in a correct format
- Console.WriteLine(ex.Message);
- }
- Input string was not in a correct format.
- In [2]:
- %%script csharp
- // 抛出自定义异常
- try
- {
- throw new Exception("出错了啊");
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
出错了啊
你可以自定义异常类, 继承 Exception 即可, 对了 C# 里面也是有 finally 的
- try
- {
- throw new Exception("出错了啊");
- //Convert.ToInt32("mmd");
- }
- catch (Exception ex)
- {
- // Input string was not in a correct format
- Console.WriteLine(ex.Message);
- }
- finally
- {
- Console.WriteLine("finally");
- }
现在一些需要 finally 的地方基本上都被 using(){}接管了, 所以特定场景会使用
先这样了
来源: https://www.cnblogs.com/dotnetcrazy/p/9219751.html