Python和很多其他语言一样,支持异常处理。我们可以使用try-catch
类似的形式捕获异常,处理异常,或者抛出异常。Python的异常命名惯例和Java语言有些不同, Java的异常一般以Exception
结尾,而Python的异常一般以Error
结尾。
常见异常
首先我们来看看常见异常,这些异常可能由于编码错误或者其他原因导致。我们打开Python解释器,然后瞎打一通代码,应该就能看到不少异常了。
SyntaxError
系统错误最常见的原因就是编码的缩进错误、或者缺少了分号、冒号等分隔符。例如下面的例子。
if 0>1
print()
File "<input>", line 1
if 0>1
^
SyntaxError: invalid syntax
NameError
这个异常通常是由于使用了未定义的名称而引起的。
fuck
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'fuck' is not defined
ZeroDivisionError
这个异常是整数除零错误,一般在数学计算的时候才会出现。
1/0
Traceback (most recent call last):
File "<input>", line 1, in <module>
ZeroDivisionError: division by zero
ValueError
ValueError
异常一般在类型转换失败的时候出现。
int('3fuck')
Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '3fuck'
处理异常
捕获异常
Java等语言的使用try-catch
结构捕获异常,在Python中也是类似的,不过捕获异常使用except
关键字。在下面的例子中如果把第一行的fuck
注释掉,就可以看到抛出了NameError
异常并由except
子句捕获了。
fuck = 'fuck!!!'
try:
fuck
except NameError:
print('This is a NameError')
多个相似的异常可以使用同一个子句捕获,这需要在except
子句中用括号包含多个异常类型。
try:
fuck
except (NameError, ValueError):
print('This is a NameError')
如果需要对不同的异常使用不同的异常子句捕获,则可以列出多个异常子句。当抛出的异常是当前异常子句中异常的实例或者子类的实例时,都会匹配到当前子句。需要注意由于所有异常的父类是Excpetion
,所以Excpetion
类型的异常必须放到最后一个,避免其他异常子句无法执行。
try:
fuck
except (NameError, ValueError):
print('This is a NameError')
except SyntaxError:
print('This is a SystemError')
except Exception:
print('This is a RuntimeError')
最后一个异常子句的异常类型也可以省略,这样就会捕获所有其他未被捕获的异常。
try:
fuck
except (NameError, ValueError):
print('This is a NameError')
except SyntaxError:
print('This is a SystemError')
except:
print('This is a RuntimeError')
如果需要获取异常信息,可以使用as
关键字声明异常变量,然后就可以在异常子句中使用了。
try:
fuck
except (NameError, ValueError) as ex:
print(f'This is a NameError:{ex}')
清理资源
如果异常处理语句中包含了系统资源(文件、网络连接、数据库连接等),我们有义务在使用完毕后及时释放这些资源。Python也提供了相应的机制。
释放资源主要通过两个子句来实现。第一个是else
子句,该子句仅当没有抛出异常的时候才执行。如果有异常,这个字句就不会被执行。第二个子句是finally
子句,不管有没有异常该语句都会执行。利用这两个语句,我们就可以优雅的关闭资源了。
try:
raise MyError()
except (NameError, ValueError) as ex:
print(f'This is a NameError:{ex}')
except MyError:
print('This is MyError')
else:
print('Else clause')
finally:
print('This is finally clause')
抛出异常
我们可以在合适的时候抛出异常,让上级调用者决定如何处理异常。
下面的例子抛出了一个自定义异常。自定义异常是继承了Exception
的类。定义之后使用raise
语句抛出异常。
class MyError(Exception):
pass
try:
raise MyError()
except (NameError, ValueError) as ex:
print(f'This is a NameError:{ex}')
except MyError:
print('This is MyError')
如果在except
子句中无法处理异常,需要再次向上级抛出,直接使用raise
关键字即可。
try:
raise MyError()
except (NameError, ValueError) as ex:
print(f'This is a NameError:{ex}')
except MyError:
print('This is MyError')
raise