Python的异常处理

1. Syntax Errors (语法错误)

语法错误,也称为解析错误,可能是您在学习 Python 时遇到的最常见的抱怨:

>>> while True print('Hello world')
File "<stdin>", line 1
while True print('Hello world')
^
SyntaxError: invalid syntax

解析器重复有问题的行并显示一个小“箭头”,指向检测到错误的行中最早的点。错误是由箭头前面的标记引起的(或至少在箭头处检测到):在示例中,在函数处检测到错误,因为在它之前缺少print()冒号 ( )。':' 打印文件名和行号,以便您知道在输入来自脚本的情况下在哪里查看。

2. Exceptions

即使语句或表达式在语法上是正确的,当尝试执行它时也可能会导致错误。在执行过程中检测到的错误称为异常并且不是无条件致命的:您很快就会学习如何在 Python 程序中处理它们。然而,大多数异常不是由程序处理的,并且会导致如下所示的错误消息:

>>> 10 * (1/0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 4 + spam*3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str

错误消息的最后一行表明发生了什么。异常有不同的类型,类型作为消息的一部分打印:示例中的类型是ZeroDivisionError,NameError和TypeError. 打印为异常类型的字符串是发生的内置异常的名称。这对于所有内置异常都是正确的,但对于用户定义的异常不必是正确的(尽管它是一个有用的约定)。标准异常名称是内置标识符(不是保留关键字)。

该行的其余部分根据异常类型及其原因提供详细信息。

错误消息的前面部分以堆栈回溯的形式显示了发生异常的上下文。一般来说,它包含一个堆栈回溯,列出源代码行;但是,它不会显示从标准输入读取的行。

内置异常列出了内置异常及其含义。

3. 处理异常

可以编写处理选定异常的程序。看下面的例子,它要求用户输入,直到输入一个有效的整数,但允许用户中断程序(使用或操作系统支持的任何东西);请注意,通过引发异常来表示用户生成的中断。Control-CKeyboardInterrupt

>>> while True:
... try:
... x = int(input("Please enter a number: "))
... break
... except ValueError:
... print("Oops! That was no valid number. Try again...")
...

try语句的工作方式如下。

首先,执行try 子句(thetryexcept关键字之间的语句)。

如果没有发生异常,则跳过 except 子句try并完成语句的执行。

如果在执行子句期间发生异常try,则跳过子句的其余部分。except然后,如果它的类型与以关键字命名的异常匹配 ,则执行except 子句,然后在 try/except 块之后继续执行。

如果发生与except 子句中指定的异常不匹配的异常,则将其传递给外部try语句;如果没有找到处理程序,则它是一个未处理的异常,并且执行停止并显示如上所示的消息。

一条try语句可能有多个except 子句,用于指定不同异常的处理程序。最多执行一个处理程序。处理程序仅处理发生在相应try 子句中的异常,而不处理同一try语句的其他处理程序中发生的异常。except 子句可以将 多个异常命名为带括号的元组,例如:

... except (RuntimeError, TypeError, NameError):
... pass

except如果子句中的类是同一个类或其基类,则子句中的类与异常兼容(但反之则不然——列出派生类的 except子句与基类不兼容)。例如,以下代码将按该顺序打印 B、C、D:

class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B")

请注意,如果将except 子句反转(使用first),它将打印 B, B, B — 第一个匹配的except 子句被触发。except B

所有异常都继承自BaseException,因此可以用作通配符。使用时要格外小心,因为用这种方式很容易掩盖真正的编程错误!它还可以用于打印错误消息,然后重新引发异常(允许调用者也处理异常):

import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except BaseException as err:
print(f"Unexpected {err=}, {type(err)=}")
raise

或者,最后一个 except 子句可以省略异常名称,但是必须从 检索异常值sys.exc_info()[1]

try...except语句有一个可选的else子句,当它出现时,它必须跟在所有except 子句之后。如果try 子句不引发异常,则它对于必须执行的代码很有用。例如:

for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except OSError:
print('cannot open', arg)
else:
print(arg, 'has', len(f.readlines()), 'lines')
f.close()

使用该else子句比在该子句中添加额外的代码要好,try因为它可以避免意外捕获不是由受try... except语句保护的代码引发的异常。

当异常发生时,它可能有一个关联的值,也称为异常的参数。参数的存在和类型取决于异常类型。

except 子句可以在异常名称之后指定一个变量。该变量绑定到一个异常实例,其参数存储在 instance.args. 为方便起见,定义了异常实例, __str__()因此可以直接打印参数而无需引用.args. 也可以在引发异常之前先实例化异常,然后根据需要向其添加任何属性。

>>> try:
... raise Exception('spam', 'eggs')
... except Exception as inst:
... print(type(inst)) # the exception instance
... print(inst.args) # arguments stored in .args
... print(inst) # __str__ allows args to be printed directly,
... # but may be overridden in exception subclasses
... x, y = inst.args # unpack args
... print('x =', x)
... print('y =', y)
...
<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs

如果异常有参数,它们将作为未处理异常的消息的最后一部分(“详细信息”)打印。

异常处理程序不仅处理在 try 子句中立即发生的异常,而且如果它们发生在 try子句中调用(甚至间接)的函数内部。例如:

>>> def this_fails():
... x = 1/0
...
>>> try:
... this_fails()
... except ZeroDivisionError as err:
... print('Handling run-time error:', err)
...
Handling run-time error: division by zero

更多异常的处理请参照 官方异常处理文档

posted @   wjxuriel  阅读(65)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示