30天学习Python 第十四天——错误处理
错误处理
没有程序是完美的,除非是一个精心编写的hello world程序 ????。
今天我要探讨的是Python中错误处理的全部内容,我尽量用平实简单的话来解释。错误处理可能是程序中最重要的概念了。
所有的应用都可能出现bug或者异常,错误是难免的。当程序由于某种未知的原因运行或执行失败时,错误通常会传递有用的信息。这可能是一个偶然的捆绑错误,可能是应用程序离线却试图访问互联网。可能是计算错误或者程序运行导致内存溢出。在我们写程序时,有很多可能出现错误。当错误发生时,程序就会停止运行,这不是我们所想要的。与其期望程序运行没有错误,更好更实用的做法是捕获错误并进行相应的处理。
在Python中,错误大致可能分为两类 —— 语法错误(Syntax Errors)和程序异常(Exceptions)。
当我们写的Python代码编译器无法确定是正确的(符合规则)代码时,就会出现语法错误。print('A grave mistake) # 少了一个引号,会出现语法错误复制代码def hello # 少了 :, 会出现语法错误
print('hello')复制代码
无论何时程序运行出现了语法错误,Python编译器都能够给出关于是哪一行代码造成了错误的详细信息。
有意义的是一些其他的错误会导致另一部分的语法错误。
我们的程序经常要接受外部的值,并且计算的执行要依赖于这些值。但这些值可能经常是不正确的。在这种情况下,就会出现错误。因此,它们需要被处理。age = input('Enter your age')if age > 18:
print('You are an adult')else:
print('You are a minor')复制代码
运行这段简单的代码会出现异常Traceback (most recent call last):
File "main.py", line 2, in if age > 18:
TypeError: '>' not supported between instances of 'str' and 'int'复制代码
这个异常是一个类型错误,因为age的值是一个字符串,所以编译器阻止了程序的运行,age需要类型转换或者转换为一个数值。age = int(input('Enter your age'))if age > 18:
print('You are an adult')else:
print('You are a minor')复制代码
现在,如果用户给的是一个字符串而不是一个数值,将会抛出另一个异常Enter your age asdf
Traceback (most recent call last):
File "main.py", line 1, in
age = int(input('Enter your age'))
ValueError: invalid literal for int() with base 10: 'asdf'复制代码
Try except语句块
为了阻止类似的错误,Python提供了try``except语句块,如果try语句块中捕获到了一个错误,将会执行except代码块。
作为对比,JavaScript中,使用的是try``catch语句块。Python只是catch的名字不一样,但功能是相似的。try:
age = int(input('Enter your age')) if age > 18:
print('You are an adult') else:
print('You are a minor')except:
print('Invalid value provided')复制代码
Else语句块
除了try except语句块,Python还提供了else,如果在try``except语句块没有捕获到异常的时候就执行else语句块中。这是try except语句的扩展。try:
age = int(input('Enter your age')) if age > 18:
print('You are an adult') else:
print('You are a minor')except:
print('Invalid value provided')else:
print('Thank You!')复制代码
Finally语句块
在程序开发中经常我们会想无论是否有异常都会执行一个动作。比如说向服务器发送日志信息。Python提供了finally块作为try except块的一部分,无论是否有异常都会执行它。try:
age = int(input('Enter your age')) if age > 18:
print('You are an adult') else:
print('You are a minor')except:
print('Invalid value provided')finally:
print('Sendiing dummy log to server') # 总是会被打印复制代码
内置异常
Python提供了许多内置的异常,它们都继承自BaseException 类
这些异常类能够用于处理特殊的异常,比如TypeError, ValueError, SystemError等from functools import reducedef calc_average(number_list):
'''
接受一个列表并且返回平均值
'''
sum = reduce(lambda acc, curr: acc + curr, number_list)
average = sum/len(number_list) return average
print(calc_average([1,2,3,4,5])) # 3.0# 传入非法参数时将会报错print(calc_average(['1','2','3','4','5'])) # TypeErrorprint(calc_average(None)) # TypeErrorprint(calc_average(3/0)) # ZeroDivisionError复制代码
为了使函数更加可靠,我们可以捕获异常from functools import reducedef calc_average(number_list):
'''
接受一个列表并且返回平均值
'''
try:sum = reduce(lambda acc, curr: acc + curr, number_list)
average = sum/len(number_list)return average except TypeError:
print('Only a list of numbers is valid')
print(calc_average('hello world')) # 输出:Only a list of numbers is valid复制代码
上面的代码捕获了非法参数。但是代码逻辑本身可能存在缺陷,可以使用单独的except块处理。from functools import reducedef calc_average(number_list):
'''
接受一个列表并且返回平均值
'''
try:sum = reduce(lambda acc, curr: acc + curr, number_list)
average = sum/len(number_list)1.0/0 # Bugreturn average except TypeError:
print('Only a list of numbers is valid') except ZeroDivisionError:
print('cannot divide by zero')
print(calc_average([1,2,3,4,5])) # cannot divide by zero'复制代码
多个异常也能够在一条语句中被同时捕获from functools import reducedef calc_average(number_list):
'''
接受一个列表并且返回平均值
'''
try:sum = reduce(lambda acc, curr: acc + curr, number_list)
average = sum/len(number_list)return average except (TypeError, ZeroDivisionError): # 处理多种情况print('Only a list of numbers is valid')
print(calc_average(['asdfasdf'])) # Only a list of numbers is valid复制代码
上面的代码处理可能的异常,但是隐藏了编译器提供的有用堆栈错误,这些信息能够告诉我们错误是哪一行代码造成的。
实际的错误消息和自定义的错误消息可以组合在一起。from functools import reducedef calc_average(number_list):
'''
接受一个列表并且返回平均值
'''
try:sum = reduce(lambda acc, curr: acc + curr, number_list)
average = sum/len(number_list)return average except TypeError as type_error:
print(f'Only a list of numbers is valid {type_error}') except ZeroDivisionError as zero_div_error:
print(f'cannot divide by zero {zero_div_error}')
print(calc_average('hello world'))
# Only a list of numbers is valid unsupported operand type(s) for /: 'str' and 'int'复制代码
这能使错误信息更有用。在Pytho中使用raise关键字也可以根据某些条件引发自定义错误name = input('Enter your name')if name.lower() == 'god': raise('Name cannot be GOD!')else:
print(name)复制代码
记住Python中所有的内置错误处理类是不可能的,除非你是专家!
Python内置异常文档可以作为处理所需异常的参考。