赞
踩
在编写Python程序时,有时我们不确定一段语句是否可以正确执行,因为如果发生错误,那么程序就会终止,这样对完整代码实现很不友好。我们希望可以程序可以根据不同的错误(异常)从而执行不同的语句,达到解决错误的效果。
为了捕获异常,在编码过程中,我们可以简单使用 try/except
语句来捕捉异常,具体语法如下:
try: # 尝试运行的语句(可能会发生异常,也可能不会发生异常)
<语句>
except (异常类型1, 异常类型2, ...): # 如果发生异常类型1时的操作
<语句>
else: # 如果没有发生异常的操作(可选)
<语句>
finally: # 不管有没有发生异常都会执行的操作
<语句>
上面的代码实现了:通过监视 try 语句块中的错误,从而让 except 语句捕获异常信息并进行处理。因此,如果你不想在异常发生时结束你的程序,就需要在 try 语句块中捕获相应的异常。
接下来,我们通过一个代码实例来具体了解一下 try...except
的用法。
try: # 尝试执行的语句(可能会发生异常,也可能不会发生异常)
file = open("test.txt", "r") # 以只读模式打开指定的文件
file.write("这是一个测试文件,用于测试Python中的异常")
except (IOError, ValueError) as e: # 可以捕获不同类型的异常,实现有针对性处理问题
print(f"捕获到的异常有 {e} ,但并不影响程序接下来的运行!")
else: # 如果没有发生异常
print("没有发生异常!")
finally: # 不管有没有异常都会执行
print("该代码块执行完毕!")
# try代码块外的程序不会收到异常影响而中断
print("[try代码块外面的其他代码] try代码块只要捕获了异常就不会影响程序的运行(除非因为处理不好导致其他地方报错:joy:)!")
"""
捕获到的异常有 not writable ,但并不影响程序接下来的运行!
该代码块执行完毕!
[try代码块外面的其他代码] try代码块只要捕获了异常就不会影响程序的运行(除非因为处理不好导致其他地方报错:joy:)!
"""
上述代码的意思是以可读模式打开一个 test.txt
文件,然后向文件中写入一段话:这是一个测试文件,用于测试Python中的异常! 因为文件是以可读模式打开的,所以没有写入权限,肯定会出错。但因在 try 代码块中,肯定会被对应的IO错误类型捕获。
我们修改代码,以写模式打开文件再写入对应的语句,修改后代码如下:
try: # 尝试执行的语句(可能会发生异常,也可能不会发生异常)
file = open("test.txt", "w") # 以只读模式打开指定的文件
file.write("这是一个测试文件,用于测试Python中的异常")
except (IOError, ValueError) as e: # 可以捕获不同类型的异常,实现有针对性处理问题
print(f"捕获到的异常有 {e} ,但并不影响程序接下来的运行!")
else: # 如果没有发生异常
print("没有发生异常!")
finally: # 不管有没有异常都会执行
print("该代码块执行完毕!")
# try代码块外的程序不会收到异常影响而中断
print("[try代码块外面的其他代码] try代码块只要捕获了异常就不会影响程序的运行(除非因为处理不好导致其他地方报错:joy:)!")
"""
没有发生异常!
该代码块执行完毕!
[try代码块外面的其他代码] try代码块只要捕获了异常就不会影响程序的运行(除非因为处理不好导致其他地方报错:joy:)!
"""
try 的工作原理是,当开始一个 try 语句后,python 就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try 子句先执行,接下来会发生什么依赖于执行时是否出现异常。大致的情况可以分为两种,一种是触发了异常,另一种是没有触发异常,具体表现如下:
如果当 try 后的代码里发生了异常,python 就跳回到 try 并执行第一个匹配该异常的 except 子句,异常处理完毕,控制流就通过整个 try 语句。
如果在 try 后的代码里没有发生异常,python将执行else语句后的语句,然后控制流通过整个try语句。
其实,上面的代码实例很好的覆盖了这两种情况。
raise
我们从来都是想方设法地让程序正常运行,为什么还要手动设置异常呢?首先要分清楚程序发生异常和程序执行错误,它们完全是两码事:
try...except...
语句或者直接debugraise 语句的基本语法格式为:
raise [exceptionName [(reason)]]
其中, exceptionName
和reason
为均可选参数,前者的作用是指定抛出的异常名称,后者为异常信息的相关描述。
也就是说,raise
语句有如下三种常用的用法:
raise
:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError
异常。raise exceptionName
:raise 后带一个异常类名称,表示引发执行类型的异常。raise exceptionName(reason)
:在引发指定类型的异常的同时,附带异常的描述信息。显然,每次执行 raise 语句,都只能引发一次执行的异常。首先,我们来测试一下以上 3 种 raise 的用法:
>>> # 1. 单独一个raise
>>> raise
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: No active exception to reraise
>>> # 2. raise exceptionName
>>> raise ZeroDivisionError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError
>>> raise NoArgumentsError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'NoArgumentsError' is not defined # exception需要符合规定,不行自己乱写
>>> NoArgumentsError = "没有参数异常"
>>> raise NoArgumentsError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: exceptions must derive from BaseException # exception需要符合规定,不行自己乱写
>>> raise Exception("NoArgumentsError")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: NoArgumentsError
>>> # 3. raise exceptionName(reason)
>>> raise ZeroDivisionError("除零错误!")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: 除零错误!
我们手动让程序引发异常,很多时候并不是为了让其崩溃。事实上,raise 语句引发的异常通常用 try except (else finally)
异常处理结构来捕获并进行处理。例如:
try:
num = input("请输入一个数字:")
if not num.isdigit():
raise ValueError(f"输入的{num}不是一个数字!")
else:
print(f"输入的数字为:{num}")
except ValueError as e: # 捕获 ValueError 并as为e
print(f"触发[{e}]异常")
"""
请输入一个数字:leovin
触发[输入的leovin不是一个数字!]异常
"""
可以看到,当用户输入的不是数字时,程序会进入 if 判断语句,并执行 raise 引发 ValueError 异常。但由于其位于 try 块中,因为 raise 抛出的异常会被 try 捕获,并由 except 块进行处理。
因此,虽然程序中使用了 raise 语句引发异常,但程序的执行是正常的,手动抛出的异常经过合适的处理并不会导致程序崩溃。
当在没有引发过异常的程序使用无参的 raise 语句时,它默认引发的是 RuntimeError 异常。例如:
try:
num = input("请输入一个数字:")
if not num.isdigit():
raise
else:
print(f"输入为: {num}")
except RuntimeError as e:
print(f"异常[{e}]触发")
"""
请输入一个数字:leovin
异常[No active exception to reraise]触发
"""
try:
num = input("请输入一个数字:")
if not num.isdigit():
raise
else:
print(f"输入为: {num}")
except:
print(f"异常触发") # 但这样我们就不知道具体是什么异常发生了!
"""
请输入一个数字:leovin
异常触发
"""
异常名称 | 描述 |
---|---|
BaseException | 所在异常的基类 |
Exception | 常规错误的基类 |
SystemExit | 解释器请求退出异常 |
KeyboardInterrupt | 用户中断执行(通常用的是Ctrl + C) |
StopIteration | 迭代器没有更多的值 |
GeneratorExit | 生成器发生异常并退出 |
StandardError | 所有的内建(built-in)标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制(堆栈溢出错误) |
ZeroDivisionError | 除零错误/取模为0错误 |
AssertionError | 断言语句条件不满足错误 |
AttributeError | 对象属性错误(一般为没有的属性被调用) |
EOFError | 没有内建输入,达到EOF标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败错误 |
OSError | 操作系统错误 |
WindowsError | 系统调用错误 |
ImportError | import失败 |
LookupError | 无效数据查询的基类 |
IndexError | 没有的索引被引用 |
KeyError | 没有的key被调用 |
MemoryError | 内存溢出错误(对Python解释器来说并不是致命错误) |
NameError | 未声明/初始化对象(没有该属性)被调用时的错误 |
UnboundLocalError | 访问未初始化的local变量(局部变量) |
ReferenceError | 弱引用(weak reference):试图访问已经被回收的对象 |
RuntimeError | 一般的运行时错误 |
NotImplementedError | 调用尚未实现的方法 |
SyntaxError | Python语法错误 |
IndentationError | 缩进错误 |
TabError | Tab和空格混用时的错误 |
SystemError | 一般的解释器系统错误 |
TypeError | 数据类型错误 |
ValueError | 传入无效值时发生的错误 |
UnicodeError | Unicode相关的错误 |
UnicodeDecodeError | Unicode解码时发生的错误 |
UnicodeEncodeError | Unicode编码时发生的错误 |
UnicodeTranslateError | Unicode转换时发生的错误 |
Warning | 警告的基类 |
DeprecationWarning | 使用弃用特征(方法)时的警告 |
FutureWarning | 构造将来语义会有改变的警告 |
OverflowWarning | 自动提升为长整型 (long) 的警告 |
PendingDeprecationWarning | 调用即将(马上)废弃特性(方法)的警告 |
RuntimeWaring | 调用可疑的运行时行为(runtime behavior)时发出的警告 |
SyntaxWarning | 可疑的语法警告 |
UserWarning | 用户代码生成的警告 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。