异常处理
所谓异常,即程序运行过程中产生的错误,会造成程序终止执行。我们都有经验,当少写了一个括号,或者缩进错误时,程序会在错误位置停止运行,并打印出错误信息,提示我们程序在某个位置出错退出了,这个流程叫做抛出异常:
deffunc():
f
print(hi)
func()
# NameError: name 'f' is not defined
def:
return'hi'
# SyntaxError: invalid syntax
处理这个异常的过程,在一个程序编写过程中至关重要,它可以保证程序能够处理各种各样的问题而不会中断执行。与其他语言经常见过的语法不同,Python的异常处理采用进行:
try:
def:
return'hi'
except:
print('An error occurred')
print("Program didn't stop here")
# An error occurred
# Program didn't stop here
通过捕获异常,我们可以避免程序遇到错误后崩溃结束。有时候,我们希望能够针对特定的异常来给出不同的处理方式,例如,对于除法操作,当用户输入的除数为0时,Python会抛出一个:
defdiv(a,b):
returna/b
a=input('Input number a: ')
b=input('Input number b: ')
a,b=int(a),int(b)
print(div(a,b))
# Input number a: 10
# Input number b: 0
# ZeroDivisionError: division by zero
此外,当用户输入一个非数字字符时,上述代码会抛出一个:
# Input number a: 10
# Input number b: x
# ValueError: invalid literal for int() with base 10: 'x'
两种情况下,程序都会终止运行。如果我们希望分别处理不同的异常,可以排列:
defdiv(a,b):
returna/b
a=input('Input number a: ')
b=input('Input number b: ')
try:
a,b=int(a),int(b)
print(div(a,b))
exceptZeroDivisionError:
print('Number b cannot be zero')
exceptValueError:
print('Input a and b must be numbers')
except:
print('Unknown error occurs')
print('Program will not end')
这样,当我们给出不同的错误输入时,会收到不同的错误提示,且程序不会直接退出:
# Input number a: 10
# Input number b: x
# Input a and b must be numbers
# Program will not end
# Input number a: 10
# Input number b: 0
# Number b cannot be zero
# Program will not end
如果我需要打印出异常的一些信息以方便调试该怎么做呢?通过语句为异常做个更名:
try:
10/
exceptZeroDivisionErrorase:
print(e)
# division by zero
直接打印可以直接查看异常信息。如果想要查看更详细的栈信息,可以利用标准库来查看:
try:
10/
exceptZeroDivisionErrorase:
importtraceback
traceback.print_exc()
print('Print here')
# Traceback (most recent call last):
# File "C:\...py", line 51, in
# 10 / 0
# ZeroDivisionError: division by zero
# Print here
这里的输出就是Python标准的错误输出,只不过这里是通过捕获异常而打印出来的,程序并不会崩溃:
10/
print('Print here')
# Traceback (most recent call last):
# File "C:\...py", line 50, in
# 10 / 0
# ZeroDivisionError: division by zero
异常语句还有一个比较有用的分句:,表示无论是否抛出了异常,异常是否处理了,程序不会崩溃或崩溃之前,都会执行的一段代码:
try:
10/
exceptZeroDivisionError:
# 捕获到异常
print('No zero')
finally:
print('In finally')
# No zero
# In finally
try:
# 无异常
10/1
except:
print('In except')
finally:
print('In finally')
# In finally
try:
10/
exceptTypeError:
# 未捕获到异常
print('Error type')
finally:
print('In finally')
print('Out of scope')
# In finally
# File "C:\...py", line 60, in
# 10 / 0
# ZeroDivisionError: division by zero
可以用于异常后的一些收尾工作,因为它无论怎样都会执行,所以适合用于关闭文件描述符,断开各类链接等结束性操作,保证在程序崩溃时,资源能够得到合理释放,避免泄露。
无所不在的else
是条件语句的最后一块:
a=-1
if(a>1):
print('if')
elifa
print('elif')
else:
print('else')
# elif
对于其他大部分语言而言,的功能就到此为止了。在Python,还活跃于很多其他地方。例如,对于一个循环,如果我们设置了一个条件,满足则在循环中途出去,或者不满足直到循环自然结束:
importrandom
num=
foriinrange(10):
if2
break
else:
num=random.randint(,10)
print(num)
这里每次循环都检查是否位于2到5之间,在则跳出循环,不在则生成新的随机整数。那么问题来了,如何知道这个循环是提前结束了还是自然结束的?在其他语言中可能我们需要增加一个标志位,在Python中可以直接利用实现:
importrandom
num=
foriinrange(10):
# 这里为了让循环不会break
if2
break
else:
num=random.randint(,10)
else:
print('Normally end')
# Normally end
这里尝试直接跳出循环:
num=
foriinrange(10):
# 这里让循环break
ifnum:
break
else:
num=random.randint(,10)
else:
print('Normally end')
#
最后的中的内容并没有打出来。所以,的存在对于很多情况下简化循环起到了非常重要的作用。例如,希望能够直接跳出嵌套循环,通常我们需要一个标志位:
flag=False
whileTrue:
whileTrue:
# 想要跳出两层循环
ifsth:
flag=True
break
ifflag:
break
我们利用可以极大地简化上面的流程:
whileTrue:
whileTrue:
ifsth:
break
else:
# 这里做普通操作
continue
break
这里我们没有引入其他变量就实现了跳出嵌套循环的功能。这里当为时,两层循环就跳出了;如果为,则会执行的内容:
sth=True
whileTrue:
whileTrue:
ifsth:
break
else:
print('Normally end inside')
continue
break
else:
print('Normally end outside')
print('Broke out')
# Broke out
在异常处理中,也很有用处。我们可以利用来增加一个无异常的分支。增加的完整异常处理流程如下图:
来看一个完整的流程:
defdiv(a,b):
returna/b
a=input('Input number a: ')
b=input('Input number b: ')
try:
a,b=int(a),int(b)
print(div(a,b))
exceptZeroDivisionError:
print('Number b cannot be zero')
exceptValueError:
print('Input a and b must be numbers')
except:
print('Unknown error occurs')
else:
print('No exception occurs')
finally:
print('This will be printed')
print('Program will not end')
# Input number a: 10
# Input number b: 2
# 5
# No exception occurs
# This will be printed
# Program will not end
大家可以通过输出情况看到整个流程的走向。何时需要捕获异常?所有需要外部的任何东西参与的地方(外部输入,外部调用,外部硬件等等)全部需要增加异常处理;所有内部的代码均不要加异常处理(自己的代码有问题叫bug)。
友情链接: https://vonalex.github.io/
欢迎关注 它不只是Python
领取专属 10元无门槛券
私享最新 技术干货