python-异常处理

异常处理

异常就是运行期检测到的错误。计算机语言针对可能出现的错误定义了异常类型,某种错误引发对应的异常时,异常处理程序将被启动,从而恢复程序的正常运行。

1. Python 标准异常总结

  • BaseException:所有异常的 基类
  • Exception:常规异常的 基类
  • StandardError:所有的内建标准异常的基类
  • ArithmeticError:所有数值计算异常的基类
  • FloatingPointError:浮点计算异常
  • OverflowError:数值运算超出最大限制
  • ZeroDivisionError:除数为零
  • AssertionError:断言语句(assert)失败
  • AttributeError:尝试访问未知的对象属性
  • EOFError:没有内建输入,到达EOF标记
  • EnvironmentError:操作系统异常的基类
  • IOError:输入/输出操作失败
  • OSError:操作系统产生的异常(例如打开一个不存在的文件)
  • WindowsError:系统调用失败
  • ImportError:导入模块失败的时候
  • KeyboardInterrupt:用户中断执行
  • LookupError:无效数据查询的基类
  • IndexError:索引超出序列的范围
  • KeyError:字典中查找一个不存在的关键字
  • MemoryError:内存溢出(可通过删除对象释放内存)
  • NameError:尝试访问一个不存在的变量
  • UnboundLocalError:访问未初始化的本地变量
  • ReferenceError:弱引用试图访问已经垃圾回收了的对象
  • RuntimeError:一般的运行时异常
  • NotImplementedError:尚未实现的方法
  • SyntaxError:语法错误导致的异常
  • IndentationError:缩进错误导致的异常
  • TabError:Tab和空格混用
  • SystemError:一般的解释器系统异常
  • TypeError:不同类型间的无效操作
  • ValueError:传入无效的参数
  • UnicodeError:Unicode相关的异常
  • UnicodeDecodeError:Unicode解码时的异常
  • UnicodeEncodeError:Unicode编码错误导致的异常
  • UnicodeTranslateError:Unicode转换错误导致的异常

异常体系内部有层次关系,Python异常体系中的部分关系如下所示:

Python异常体系中的部分关系

2. Python标准警告总结

  • Warning:警告的基类
  • DeprecationWarning:关于被弃用的特征的警告
  • FutureWarning:关于构造将来语义会有改变的警告
  • UserWarning:用户代码生成的警告
  • PendingDeprecationWarning:关于特性将会被废弃的警告
  • RuntimeWarning:可疑的运行时行为(runtime behavior)的警告
  • SyntaxWarning:可疑语法的警告
  • ImportWarning:用于在导入模块过程中触发的警告
  • UnicodeWarning:与Unicode相关的警告
  • BytesWarning:与字节或字节码相关的警告
  • ResourceWarning:与资源使用相关的警告

3. try - except 语句

try:
    检测范围
except Exception[as reason]:
    出现异常后的处理代码

try 语句按照如下方式工作:

  • 首先,执行try子句(在关键字try和关键字except之间的语句)
  • 如果没有异常发生,忽略except子句,try子句执行后结束。
  • 如果在执行try子句的过程中发生了异常,那么try子句余下的部分将被忽略。如果异常的类型和except之后的名称相符,那么对应的except子句将被执行。最后执行try - except语句之后的代码。
  • 如果一个异常没有与任何的except匹配,那么这个异常将会传递给上层的try中。

【例子】

try:
    f = open('test.txt')
    print(f.read())
    f.close()
except OSError:
    print('打开文件出错')

# 打开文件出错
[root@10 python]# ls test.txt
ls: 无法访问'test.txt': 没有那个文件或目录
[root@10 python]# py try-except.py 
打开文件出错
[root@10 python]# echo -n "测试" > test.txt
[root@10 python]# py try-except.py 
测试
[root@10 python]# 

这段代码的作用是尝试打开名为"test.txt"的文件,如果打开成功,则读取文件内容并打印出来,最后关闭文件。如果打开文件出错(比如文件不存在或无法访问),则会捕获 OSError 异常并打印出"打开文件出错"。

解释一下代码的执行过程:

  • 首先,尝试打开名为"test.txt"的文件,如果文件存在且可以被访问,则执行下面的代码块;否则跳到 except 语句。
  • 打开文件后,使用 f.read() 方法读取文件内容,并通过 print() 函数打印出来。
  • 最后,使用 f.close() 关闭文件,确保资源被正确释放。
  • 如果在 try 代码块中发生了 OSError 异常(比如文件无法打开),那么程序会跳到 except 语句,并执行其中的代码,打印出"打开文件出错"。

注意:使用 try-except 结构可以捕获指定类型的异常,并在出现异常时执行特定的错误处理代码,避免程序崩溃。

【例子】

try:
    f = open('test.txt')
    print(f.read())
    f.close()
except OSError as error:
    print('打开文件出错\n原因是:' + str(error))

# 打开文件出错
# 原因是:[Errno 2] No such file or directory: 'test.txt'
[root@10 python]# rm -f test.txt 
[root@10 python]# py try-except_2.py 
打开文件出错
原因是:[Errno 2] No such file or directory: 'test.txt'
[root@10 python]# 

这段代码与之前的代码相似,但在 except 块中做了一些修改。现在,代码会捕获 OSError 异常,并将异常信息打印出来。

解释一下代码的执行过程:

  • 首先,尝试打开名为"test.txt"的文件,如果文件存在且可以被访问,则执行下面的代码块;否则跳到 except 语句。
  • 打开文件后,使用 f.read() 方法读取文件内容,并通过 print() 函数打印出来。
  • 最后,使用 f.close() 关闭文件,确保资源被正确释放。
  • 如果在 try 代码块中发生了 OSError 异常(比如文件无法打开),那么程序会跳到 except 语句,并执行其中的代码。
  • as error 表示将捕获的异常对象赋值给变量 error
  • except 块中,使用 print() 函数将错误提示信息打印出来,包括捕获到的异常信息。

这样,即可打印出出错的原因,帮助调试程序或提供错误信息。

3.1 一个try语句可能包含多个except子句,分别来处理不同的特定的异常。最多只有一个分支会被执行。**

【例子】

try:
    int("abc")
    s = 1 + '1'
    f = open('test.txt')
    print(f.read())
    f.close()
except OSError as error:
    print('打开文件出错\n原因是:' + str(error))
except TypeError as error:
    print('类型出错\n原因是:' + str(error))
except ValueError as error:
    print('数值出错\n原因是:' + str(error))

# 数值出错
# 原因是:invalid literal for int() with base 10: 'abc'
[root@10 python]# ls test.txt 
ls: 无法访问'test.txt': 没有那个文件或目录
[root@10 python]# py try-except_3.py 
数值出错
原因是:invalid literal for int() with base 10: 'abc'
[root@10 python]# sed -i.bak 's|abc|123|' try-except_3.py
[root@10 python]# sed -n '/int(.....)/'p try-except_3.py
    int("123")
[root@10 python]# py try-except_3.py 
类型出错
原因是:unsupported operand type(s) for +: 'int' and 'str'
[root@10 python]# sed -i.bak2 "s#'1'#1#" try-except_3.py
[root@10 python]# sed -n '/s =/'p try-except_3.py
    s = 1 + 1
[root@10 python]# py try-except_3.py
打开文件出错
原因是:[Errno 2] No such file or directory: 'test.txt'
[root@10 python]# echo -n "测试" > test.txt
[root@10 python]# py try-except_3.py
测试
[root@10 python]#

这段代码中使用了多个 except 块来捕获不同类型的异常,并打印出对应的错误信息。

解释一下代码的执行过程:

  • 首先,尝试将字符串 "abc" 转换为整数,由于该字符串不能被正确转换,抛出了 ValueError 异常。这时,程序会跳到第一个 except 块中。
  • 在第一个 except 块中,使用 print() 函数打印出错误提示信息,包括捕获的异常信息。在这里,打印出了“数值出错\n原因是:invalid literal for int() with base 10: 'abc'”。
  • 接下来,由于前面的语句发生了异常,程序不会继续执行剩余的代码。
  • 注意,第二个和第三个 except 块不会执行,因为这里抛出的异常是 ValueError,而不是 OSErrorTypeError

使用多个 except 块可以根据不同的异常类型,进行不同的错误处理。这样能够更精确地捕获和处理异常,提高代码的健壮性。

3.2 try-except-else 语句

【例子】

dict1 = {'a': 1, 'b': 2, 'v': 22}
try:
    x = dict1['y']
except LookupError:
    print('查询错误')
except KeyError:
    print('键错误')
else:
    print(x)

# 查询错误
[root@10 python]# py try-except-else.py 
查询错误
[root@10 python]# vi try-except-else.py 
[root@10 python]# cat try-except-else.py 
dict1 = {'a': 1, 'b': 2, 'v': 22}
try:
    x = dict1['y']
except KeyError:
    print('键错误')
except LookupError:
    print('查询错误')
else:
    print(x)

[root@10 python]# py try-except-else.py 
键错误
[root@10 python]# sed -i.bak "s/'y'/'a'/" try-except-else.py
[root@10 python]# sed -n '/a/'p try-except-else.py 
dict1 = {'a': 1, 'b': 2, 'v': 22}
    x = dict1['a']
[root@10 python]# py try-except-else.py
1
[root@10 python]# 

这段代码中使用了 try-except-else 结构来处理字典的查询操作。

解释一下代码的执行过程:

  • 首先,尝试从 dict1 字典中查询键 'y' 对应的值,由于该键不存在,抛出了 KeyError 异常。这时,程序会跳到第一个 except 块中。
  • 在第一个 except 块中,使用 print() 函数打印出错误提示信息,即"查询错误"。
  • 由于发生了异常,程序不会继续执行 else 块中的代码。
  • 注意,这里使用了 LookupError 作为第一个 except 块的异常类型,它是 KeyError 的父类,因此可以捕获 KeyError 异常。
  • 所以,使用多个except代码块时,必须坚持对其规范排序,要从最具针对性的异常到最通用的异常。

通过 try-except-else 结构,我们可以在 try 块中尝试执行某个操作,如果发生异常,则执行特定的异常处理代码(如 except 块),如果没有发生异常,则执行其他的代码(如 else 块)。这样可以使代码更加灵活和健壮。

3.3 一个 except 子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组。

【例子】

try:
    int("abc")
    s = 1 + '1'
    f = open('test.txt')
    print(f.read())
    f.close()
except (OSError, TypeError, ValueError) as error:
    print('出错了!\n原因是:' + str(error))

# 出错了
# 原因是:invalid literal for int() with base 10: 'abc'

这段代码中使用了一个 except 块来捕获多个异常类型,并打印出对应的错误信息。

解释一下代码的执行过程:

  • 首先,尝试将字符串 "abc" 转换为整数,由于该字符串不能被正确转换,抛出了 ValueError 异常。
  • 接着,由于前面的语句发生了异常,程序不会继续执行剩余的代码。
  • except 块中,使用 (OSError, TypeError, ValueError) 表示同时捕获这三种异常类型。然后,将捕获的异常对象赋值给变量 error
  • except 块中,使用 print() 函数打印出错误提示信息,包括捕获的异常信息。在这里,打印出了“出错了!\n原因是:invalid literal for int() with base 10: 'abc'”。

通过使用括号((OSError, TypeError, ValueError))将多个异常类型放在一起,可以在单个 except 块中捕获多个异常。这样简化了代码,并减少了重复的代码判断。

元组内的异常类型顺序对结果没有影响。
try 语句块中的语句段顺序对结果有影响,谁在前并当发生异常时,就先输出谁并终止代码执行。

感谢你的指正,我会更加准确地回答你的问题。非常抱歉之前的回答有误。谢谢!


4. try - except - finally 语句

try:
检测范围
except Exception[as reason]:
出现异常后的处理代码
finally:
无论如何都会被执行的代码

不管try子句里面有没有发生异常,finally子句都会执行。

【例子】如果一个异常在try子句里被抛出,而又没有任何的except把它截住,那么这个异常会在finally子句执行后被抛出。

def divide(x, y):
    try:
        result = x / y
        print("result is", result)
    except ZeroDivisionError:
        print("division by zero!")
    finally:
        print("executing finally clause")


divide(2, 1)
# result is 2.0
# executing finally clause
divide(2, 0)
# division by zero!
# executing finally clause
divide("2", "1")
# executing finally clause
# TypeError: unsupported operand type(s) for /: 'str' and 'str'
[root@10 python]# py try-except-finally.py 
result is 2.0
executing finally clause
division by zero!
executing finally clause
executing finally clause
Traceback (most recent call last):
  File "/root/python/try-except-finally.py", line 17, in <module>
    divide("2", "1")
  File "/root/python/try-except-finally.py", line 3, in divide
    result = x / y
TypeError: unsupported operand type(s) for /: 'str' and 'str'
[root@10 python]#

这段代码中,divide函数用于执行两个数的除法操作。它使用了try-except-finally语句块来处理可能出现的异常情况。

当传入的两个参数xy都是数值类型时,try块中的除法操作将正常执行,结果将存储在result变量中,并通过print语句打印出来。然后,无论是否有异常发生,finally块中的代码都会执行,打印出"executing finally clause"的消息。

当传入的y为0时,会发生ZeroDivisionError异常,except块中的代码将执行,打印出"division by zero!"的消息。然后,无论是否有异常发生,finally块中的代码仍然会执行,打印出"executing finally clause"的消息。

当传入的参数x和y都是字符串类型时,由于字符串不支持除法操作,将抛出TypeError异常。在这种情况下,except块中的代码不会执行,而是直接跳过并执行finally块中的代码,打印出"executing finally clause"的消息,并输出错误信息。


5. try - except - else 语句

如果在try子句执行时没有发生异常,Python将执行else语句后的语句。

try:
    检测范围
except:
    出现异常后的处理代码
else:
    如果没有异常执行这块代码

使用except而不带任何异常类型,这不是一个很好的方式,我们不能通过该程序识别出具体的异常信息,因为它捕获所有的异常。

try:
检测范围
except(Exception1[, Exception2[,...ExceptionN]]]):
发生以上多个异常中的一个,执行这块代码
else:
如果没有异常执行这块代码

【例子】

try:
    fh = open("testfile.txt", "w")
    fh.write("这是一个测试文件,用于测试异常!!")
except IOError:
    print("Error: 没有找到文件或读取文件失败")
else:
    print("内容写入文件成功")
    fh.close()

# 内容写入文件成功

这段代码是一个文件操作的示例,让我解释一下它的执行流程:

  1. 首先,代码尝试打开文件 "testfile.txt" 并以写入模式打开。如果文件不存在,将创建一个新文件。这部分逻辑被放在 try 块中。

  2. 如果文件打开成功,代码会执行 fh.write("这是一个测试文件,用于测试异常!!") 来向文件写入内容。

  3. 如果文件打开或写入过程中发生了输入/输出(IO)错误,例如文件无法找到或无法读取,那么程序会跳转到 except IOError 块中,并打印 "Error: 没有找到文件或读取文件失败"。

  4. 如果文件打开和写入都成功完成且未发生任何错误,那么程序会执行 else 块中的代码,打印 "内容写入文件成功",然后关闭文件。

总结起来,这段代码尝试打开文件并写入内容,如果在这个过程中发生了IO错误,则会捕获并处理异常。如果没有发生错误,代码会执行相应的成功逻辑,并在最后关闭文件。

注意:else语句的存在必须以except语句的存在为前提,在没有except语句的try语句中使用else语句,会引发语法错误。


6. raise语句

Python 使用raise语句抛出一个指定的异常。

【例子】

try:
    raise NameError('HiThere')
except NameError:
    print('An exception flew by!')
    
# An exception flew by!

这段代码演示了如何使用 raise 语句主动引发一个异常,并使用 try-except 结构捕获并处理该异常。让我解释一下它的执行流程:

  1. try 块中,使用 raise 语句引发了一个 NameError 异常,异常的错误信息为 'HiThere'

  2. 因为在 except NameError 中指定了捕获 NameError 类型的异常,所以代码会跳转到该 except 块中。

  3. except 块中,会打印出字符串 "An exception flew by!"。

总结起来,这段代码通过 raise 语句主动引发了一个 NameError 异常,并在 try-except 结构中捕获和处理了该异常。当异常被引发时,代码会跳转到与异常类型匹配的 except 块中执行相应的逻辑。

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

推荐阅读更多精彩内容

  • 异常处理 异常Exception 错误 Error :错误是可以避免的逻辑错误:算法写错了,加法写成了减法笔误:变...
    vampire6阅读 1,073评论 0 0
  • 异常处理: 对出现的异常做出相应处理 Python中的异常处理能力是很强大的,可向用户准确反馈出错信息。在Pyt...
    黑妮zym阅读 243评论 0 0
  • 版本:python2.7 系统:Mac OSX 异常处理是代替日渐衰落的error code方法的新法,提供e...
    和黑黑阅读 1,222评论 0 3
  • 在日常的程序开发当中,我们肯定是会遇到一些异常的。Python有提供异常处理的方式——try/except,这篇博...
    阿博聊编程阅读 103评论 0 2
  • 一、了解异常 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。 一般情况下,在Python无...
    ThreeYear_xin阅读 169评论 0 0