Python - 异常处理



Python 中的异常处理

Python 中的异常处理是指管理程序执行期间可能发生的运行时错误。在 Python 中,当程序执行过程中出现错误或意外情况时,例如被零除、尝试访问不存在的文件或尝试对不兼容的数据类型执行操作,则会引发异常。

Python 提供了两个非常重要的功能来处理 Python 程序中的任何意外错误并在其中添加调试功能 -

  • 异常处理 − 本教程将对此进行介绍。以下是 Python 中可用的标准异常列表:标准异常
  • 断言 − 这将在 Python 中的断言教程中介绍。

Python 中的断言

断言是一种健全性检查,您可以在完成程序测试后打开或关闭它。

考虑断言的最简单方法是将其比作 raise-if 语句(或者更准确地说,raise-if-not 语句)。测试表达式,如果结果为 false,则会引发异常。

断言由 assert 语句执行,这是 Python 的最新关键字,在 1.5 版中引入。

程序员通常将断言放在函数的开头以检查有效的输入,并在函数调用之后放置断言以检查有效的输出。

assert 语句

当遇到 assert 语句时,Python 会计算随附的表达式,希望这是真的。如果表达式为 false,则 Python 会引发 AssertionError 异常。

assert 的语法是 −


 assert Expression[, Arguments]

如果断言失败,Python 将使用 ArgumentExpression 作为 AssertionError 的参数。可以使用 try-except 语句像任何其他异常一样捕获和处理 AssertionError 异常,但如果不处理,它们将终止程序并产生回溯。

这是一个将温度从开尔文度转换为华氏度的函数。由于零开尔文是最冷的,因此如果它看到负温度,该函数就会退出 -


def KelvinToFahrenheit(Temperature):
	 	assert (Temperature >= 0),"Colder than absolute zero!"
	 	return ((Temperature-273)*1.8)+32
print (KelvinToFahrenheit(273))
print (int(KelvinToFahrenheit(505.78)))
print (KelvinToFahrenheit(-5))

执行上述代码时,它会产生以下结果 -

32.0
451
Traceback (most recent call last):
File "test.py", line 9, in <module>
print (KelvinToFahrenheit(-5))
File "test.py", line 4, in KelvinToFahrenheit
assert (Temperature >= 0),"Colder than absolute zero!"
AssertionError: Colder than absolute zero!

什么是异常?

异常是在程序执行期间发生的事件,该事件会中断程序指令的正常流程。通常,当 Python 脚本遇到无法处理的情况时,它会引发异常。异常是表示错误的 Python 对象。

当 Python 脚本引发异常时,它必须立即处理异常,否则它将终止并退出。

在 Python 中处理异常

如果您有一些可能引发异常的可疑代码,则可以通过将可疑代码放在 try: 块中来保护您的程序。在 try: 块之后,包含一个 except: 语句,后跟一个代码块,该代码块可以尽可能优雅地处理问题。

  • try: 块包含易发生异常的语句
  • 如果发生 exception,程序会跳转到 except: 块。
  • 如果 try: 块中没有异常,则跳过 except: 块。

语法

以下是 try...except...else 块 -


try:
	 	You do your operations here
	 	......................
except ExceptionI:
	 	If there is ExceptionI, then execute this block.
except ExceptionII:
	 	If there is ExceptionII, then execute this block.
	 	......................
else:
	 	If there is no exception then execute this block.

以下是有关上述语法的几个要点 -

  • 单个 try 语句可以有多个 except 语句。当 try 块包含可能引发不同类型异常的语句时,这很有用。
  • 您还可以提供一个泛型 except 子句,用于处理任何异常。
  • 在 except 子句之后,可以包含 else 子句。如果 try: 块中的代码未引发异常,则执行 else 块中的代码。
  • else 块是不需要 try: 块保护的代码的好地方。

此示例打开一个文件,在文件中写入内容,然后优雅地出来,因为根本没有问题。


try:
	 	fh = open("testfile", "w")
	 	fh.write("This is my test file for exception handling!!")
except IOError:
	 	print ("Error: can\'t find file or read data")
else:
	 	print ("Written content in the file successfully")
	 	fh.close()

它将产生以下输出 -

Written content in the file successfully

但是,将 open() 函数中的 mode 参数更改为 “w”。如果 testfile 尚不存在,则程序在 except 块中遇到 IOError,并打印以下错误消息 -

Error: can't find file or read data

此示例尝试打开您没有写入权限的文件,因此会引发异常 -


try:
	 	fh = open("testfile", "r")
	 	fh.write("This is my test file for exception handling!!")
except IOError:
	 	print ("Error: can\'t find file or read data")
else:
	 	print ("Written content in the file successfully")

这将产生以下结果 -

Error: can't find file or read data

无例外的 except 子句

您还可以使用 except 语句,没有例外,定义如下 -


try:
	 	You do your operations here;
	 	......................
except:
	 	If there is any exception, then execute this block.
	 	......................
else:
	 	If there is no exception then execute this block.	

这种 try-except 语句捕获发生的所有异常。但是,使用这种 try-except 语句并不被认为是一种好的编程习惯,因为它捕获了所有异常,但不会使程序员确定可能发生的问题的根本原因。

具有多个异常的 except 子句

您还可以使用相同的 except 语句来处理多个异常,如下所示 -


try:
	 	You do your operations here;
	 	......................
except(Exception1[, Exception2[,...ExceptionN]]]):
	 	If there is any exception from the given exception list,	
	 	then execute this block.
	 	......................
else:
	 	If there is no exception then execute this block.	

try-finally 子句

您可以将 finally: 块与 try: 块一起使用。finally 块是放置任何必须执行的代码的地方,无论是 try 块 引发异常与否。try-finally 语句的语法是这样的 -


try:
	 	You do your operations here;
	 	......................
	 	Due to any exception, this may be skipped.
finally:
	 	This would always be executed.
	 	......................

您不能将 else 子句与 finally 子句一起使用。


try:
	 	fh = open("testfile", "w")
	 	fh.write("This is my test file for exception handling!!")
finally:
	 	print ("Error: can\'t find file or read data")

如果您没有以写入模式打开文件的权限,则将产生以下结果 -

Error: can't find file or read data

相同的示例可以写得更简洁,如下所示 -


try:
	 	fh = open("testfile", "w")
	 	try:
	 	 	 fh.write("This is my test file for exception handling!!")
	 	finally:
	 	 	 print ("Going to close the file")
	 	 	 fh.close()
except IOError:
	 	print ("Error: can\'t find file or read data")

当 try 块中引发异常时,执行会立即传递到 finally 块。执行 finally 块中的所有语句后,将再次引发异常,如果存在在 try-except 语句的下一个更高层,则在 except 语句中处理异常。

异常的参数

异常可以具有参数,该参数是提供有关问题的其他信息的值。参数的内容因异常而异。您可以通过在 except 子句中提供变量来捕获异常的参数,如下所示 -


try:
	 	You do your operations here;
	 	......................
except ExceptionType, Argument:
	 	You can print value of Argument here...

如果编写代码来处理单个异常,则可以在 except 语句中让变量跟在异常名称后面。如果要捕获多个异常,则可以让变量跟随异常的元组。

此变量接收异常的值,主要包含异常的原因。该变量可以接收单个值或元组形式的多个值。此 Tuples 通常包含错误字符串、错误号和错误位置。

以下是单个异常的示例 -


# Define a function here.
def temp_convert(var):
	 	try:
	 	 	 return int(var)
	 	except ValueError as Argument:
	 	 	 print ("The argument does not contain numbers\n", Argument)

# Call above function here.
temp_convert("xyz")

这将产生以下结果 -

The argument does not contain numbers
invalid literal for int() with base 10: 'xyz'

引发异常

使用 raise 语句,可以通过多种方式引发异常。raise 语句的一般语法如下。

语法


raise [Exception [, args [, traceback]]]

此处,Exception 是异常的类型(例如 NameError),argument 是 exception 参数的值。参数是可选的;如果未提供,则 exception 参数为 None。

最后一个参数 trace back 也是可选的(在实践中很少使用),如果存在,则为用于异常的 traceback 对象。

异常可以是字符串、类或对象。Python 核心引发的大多数异常都是类,其参数是类的实例。定义新的异常非常简单,可以按如下方式完成 -


 def functionName( level ):
	 	if level < 1:
	 	 	 raise "Invalid level!", level
	 	 	 # The code below to this would not be executed
	 	 	 # if we raise the exception

注意:为了捕获异常,“except” 子句必须引用引发的相同异常 类 object 或简单字符串。例如,要捕获上述异常,我们必须编写 except 子句,如下所示 -


try:
	 	Business Logic here...
except "Invalid level!":
	 	Exception handling here...
else:
	 	Rest of the code here...

用户定义的异常

Python 还允许您通过从标准内置异常派生类来创建自己的异常。

下面是一个与 RuntimeError 相关的示例。在这里,创建了一个从 RuntimeError 子类化的类。当您需要在捕获异常时显示更具体的信息时,这非常有用。

在 try 块中,用户定义的异常在 except 块中引发并捕获。变量 e 用于创建类 Networkerror 的实例。


class Networkerror(RuntimeError):
	 	def __init__(self, arg):
	 	 	 self.args = arg

因此,一旦定义了上面的类,就可以按如下方式引发异常 -


try:
	 	raise Networkerror("Bad hostname")
except Networkerror,e:
	 	print (e.args)

标准异常

以下是 Python 中可用的标准异常列表 -

异常名称 描述
Exception 所有异常的基类
StopIteration 当迭代器的 next() 方法不指向任何对象时引发。
SystemExit 由 sys.exit() 函数引发。
StandardError 除 StopIteration 和 SystemExit 之外的所有内置异常的基类。
ArithmeticError 数值计算中出现的所有错误的基类。
OverflowError 当计算超过数值类型的最大限制时引发。
FloatingPointError 浮点计算失败时引发。
ZeroDivisionError 当所有数值类型都被零除或取模时,将引发。
AssertionError 在 Assert 语句失败时引发。
AttributeError 在属性引用或赋值失败时引发。
EOFError 当 raw_input() 或 input() 函数没有输入并且到达文件末尾时引发。
ImportError 当 import 语句失败时引发。
KeyboardInterrupt 当用户中断程序执行时引发,通常按 Ctrl+c。
LookupError 所有查找错误的基类。
IndexError 在序列中找不到索引时引发。
KeyError 在字典中找不到指定的键时引发。
NameError 在本地或全局命名空间中找不到标识符时引发。
UnboundLocalError 尝试访问函数或方法中的局部变量,但未为其分配值时引发。
EnvironmentError 在 Python 环境之外发生的所有异常的基类。
IOError 当 input/output 操作失败时引发,例如 print 语句或 open() 函数在尝试打开不存在的文件时。
IOError 针对操作系统相关错误引发。
SyntaxError 当 Python 语法出现错误时引发。
IndentationError 未正确指定缩进时引发。
SystemError 当解释器发现内部问题时引发,但遇到此错误时,Python 解释器不会退出。
SystemExit 使用 sys.exit() 函数退出 Python 解释器时引发。如果未在代码中处理,则会导致解释器退出。
TypeError 当尝试对指定数据类型无效的操作或函数时引发。
ValueError 当数据类型的内置函数具有有效类型的参数,但参数指定的值无效时引发。
RuntimeError 当生成的错误不属于任何类别时引发。
NotImplementedError 当需要在继承类中实现的抽象方法未实际实现时引发。