异常

Python
作者

yangjh

发布于

2022年5月19日

异常是指程序中的例外,违例情况。异常机制是指程序出现错误后,程序的处理方法。当出现错误后,程序的执行流程发生改变,程序的控制权转移到异常处理。

捕获异常

异常处理可以使开发人员能以优雅的方式处理错误。

try-except

Python使用try-except语句处理异常。语法如下:

try:
    # write some code
    # that might throw exception
except <ExceptionType>:
    # Exception handler, alert the user

在try语句块中,我们写入可能会产生异常的代码,当异常发生时,try语句块中的代码会被忽略,转而进入except语句块中处理异常。例如:

try:
    f = open('somefile.txt', 'r')
    print(f.read())
    f.close()
except IOError:
    print('file not found')

上述代码的执行流程如下:

  1. 先执行介于try和except之间的语句。
  2. 如果没有异常,则except语句块中的代码会被跳过。
  3. 如果文件不存在,则产生异常,在try语句块中的其他代码会被跳过。
  4. 当异常发生时,如果异常类型和except关键字后的异常名称匹配,就执行except分支中的代码。上述代码中只能处理IOError异常,如要处理其他类型的异常,还需要添加更多的except分支。

多个except

try声明可以有多个except分支,它还可以选择else和finally分支。语法如下:

try:
    <body>
except <ExceptionType1>:
    <handler1>
except <ExceptionTypeN>:
    <handlerN>
except:
    <handlerExcept>
else:
    <process_else>
finally:
    <process_finally>

except分支类似于elif。当异常发生时,将检查except分支是否和异常类型匹配。如果匹配,就执行对应except分支中的代码。在最后一个except分支中,异常类型是被忽略了的。如果异常发生,但没有匹配到最后一个except之前的分支,则最后的except分支中的代码会被执行。如果没有任何异常发生,则执行else语句中的代码。finally分支中的代码,无论是否有异常发生,都会被执行。例如:

try:
    num1, num2 = eval(input("Enter two numbers, separated by a comma : "))
    result = num1 / num2
    print("Result is", result)

except ZeroDivisionError:
    print("Division by zero is error !!")

except SyntaxError:
    print("Comma is missing. Enter numbers separated by comma like this 1, 2")

except:
    print("Wrong input")

else:
    print("No exceptions")

finally:
    print("This will execute no matter what")

eval()函数允许在Python程序内部运行Python代码,了解更多关于eval()的信息,请访问http://stackoverflow.com/questions/9383740/what-does-pythons-eval-do

自定义异常

使用关键字raise,可以在方法中自定义异常。语法为:

raise ExceptionClass("Your argument")

例如:

def enterage(age):
    if age < 0:
        raise ValueError("Only positive integers are allowed")

    if age % 2 == 0:
        print("age is even")
    else:
        print("age is odd")

try:
    num = int(input("Enter your age: "))
    enterage(num)

except ValueError:
    print("Only positive integers are allowed")
except:
    print("something is wrong")

当用户输入的年龄小于0时,程序显示结果为:

only positive integers are allowed

with关键字

with表达式其实是try-finally的简写形式。但是又不是全相同。

try:
    f=open('xxx')
except:
    print('fail to open')
    exit(-1)
try:
    do something
except:
    do something
finally:
    f.cLose()

虽然这段代码运行良好,但比较冗长。而使用with的话,能够减少冗长,还能自动处理上下文环境产生的异常。如下面代码:

"""
格式
with context [as var]:
    pass
"""

其中的context是一个表达式,返回的是一个对象,var用来保存context表达式返回的对象,可以有单个或者多个返回值。

with open('1.txt') as f:
    print(f.read())
    
print(f.closed)

表达式open('1.txt')返回是一个io.TextIOWrapper 类型的变量用f接受到。在with语句块中就可以使用这个变量操作文件。执行with这个结构之后,f会自动关闭。相当于自带了一个finally

但是with本身并没有异常捕获的功能,但是如果发生了运行时异常,它照样可以关闭文件释放资源。

with 语句实质是上下文管理:

  1. 上下文管理协议。包含方法__enter__()__exit_(),支持该协议对象要实现这两个方法。
  2. 上下文管理器,定义执行with语句时要建立的运行时上下文,负责执行with语句块上下文中的进入与退出操作。
  3. 进入上下文的时候执行__enter__方法,如果设置as var语句,var变量接受__enter__()方法返回值
  4. 如果运行时发生了异常,就退出上下文管理器。调用管理器__exit__方法。