Python - 异常处理



Python中的异常处理

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

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

  • 异常处理 - 本教程将对此进行介绍。以下是 Python 中提供的标准异常列表:标准异常

  • 断言 - 这将在Python 中的断言 教程中介绍。

Python 中的断言

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

最简单的理解断言的方法是将其比作raise-if语句(更准确地说,是raise-if-not语句)。测试一个表达式,如果结果为假,则引发异常。

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

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

assert 语句

当遇到assert语句时,Python会评估随附的表达式,该表达式应该为真。如果表达式为假,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: 块包含可能引发异常的语句。

  • 如果发生异常,程序跳转到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.
   ......................

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

示例

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语句中进行处理。

异常的参数

异常可以有一个参数,它是一个提供有关问题更多信息的 value。参数的内容因异常而异。你可以通过在except子句中提供一个变量来捕获异常的参数,如下所示:

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

如果你编写代码来处理单个异常,你可以在except语句中在异常名称后添加一个变量。如果你正在捕获多个异常,你可以在异常元组后添加一个变量。

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

示例

以下是单个异常的示例:

# 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是异常参数的值。参数是可选的;如果未提供,则异常参数为None。

最终参数,回溯,也是可选的(在实践中很少使用),如果存在,则是用于异常的回溯对象。

示例

异常可以是字符串、类或对象。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”子句必须引用抛出的相同异常,无论是类对象还是简单的字符串。例如,要捕获上述异常,我们必须按如下方式编写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中提供的标准异常列表:

序号 异常名称和描述
1

异常

所有异常的基类

2

StopIteration

当迭代器的next()方法不指向任何对象时引发。

3

SystemExit

由sys.exit()函数引发。

4

StandardError

除StopIteration和SystemExit之外的所有内置异常的基类。

5

ArithmeticError

所有针对数字计算发生的错误的基类。

6

OverflowError

当计算超过数值类型的最大限制时引发。

7

FloatingPointError

当浮点计算失败时引发。

8

ZeroDivisionError

当对所有数字类型进行除法或模零运算时引发。

9

AssertionError

在Assert语句失败的情况下引发。

10

AttributeError

在属性引用或赋值失败的情况下引发。

11

EOFError

当raw_input()或input()函数没有输入并且到达文件结尾时引发。

12

ImportError

当import语句失败时引发。

13

KeyboardInterrupt

当用户中断程序执行时引发,通常是通过按Ctrl+c。

14

LookupError

所有查找错误的基类。

15

IndexError

当在序列中找不到索引时引发。

16

KeyError

当在字典中找不到指定的键时引发。

17

NameError

当在本地或全局命名空间中找不到标识符时引发。

18

UnboundLocalError

当尝试访问函数或方法中的局部变量但未为其赋值时引发。

19

EnvironmentError

发生在Python环境之外的所有异常的基类。

20

IOError

当输入/输出操作失败时引发,例如print语句或open()函数在尝试打开不存在的文件时。

21

IOError

针对与操作系统相关的错误引发。

22

SyntaxError

当Python语法错误时引发。

23

IndentationError

当缩进未正确指定时引发。

24

SystemError

当解释器发现内部问题时引发,但是当遇到此错误时,Python解释器不会退出。

25

SystemExit

当使用sys.exit()函数退出Python解释器时引发。如果代码中未处理,则导致解释器退出。

26

TypeError

当尝试对指定数据类型无效的操作或函数时引发。

27

ValueError

当数据类型的内置函数具有有效的参数类型,但参数具有指定的无效值时引发。

28

RuntimeError

当生成的错误不属于任何类别时引发。

29

NotImplementedError

当需要在继承类中实现的抽象方法实际上未实现时引发。

广告