有的错误是程序编写有问题造成的,比如本来应该输出整数结果输出了字符串,这种错误我们通常称之为bug,bug是必须修复的。
有的错误是用户输入造成的,比如让用户输入email地址,结果得到一个空字符串,这种错误可以通过检查用户输入来做相应的处理。
还有一类错误是完全无法在程序运行过程中预测的,比如写入文件的时候,磁盘满了,写不进去了,或者从网络抓取数据,网络突然断掉了。这类错误也称为异常,在程序中通常是必须处理的,否则,程序会因为各种问题终止并退出。
一、 异常
异常就是程序运行时发生的错误信号,在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止。
异常分为三部分:
- 异常追踪信息
- 异常类型
- 异常值
错误
- 语法错误:不符合语法规定,比如多缩进少缩进
- 逻辑错误:语法正确,但也有如除于0这样的逻辑问题
常见异常类型
异常名称 | 描述 |
AttributeError | 试图访问一个对象没有的属性 |
IOError | 输入/输出异常;基本上是无法打开文件 |
ImportError | 无法引入模块或包;基本上是路径问题或名称错误 |
IndentationError | 语法错误(的子类);代码没有正确对齐 |
IndexError | 下标索引超出序列边界,试图访问不存在的索引 |
KeyError | 试图访问字典中不存在的键 |
KeyboardInterrupt | 用户按下了 Ctrl+C 键中断程序执行 |
NameError | 使用一个还未被赋值的变量 |
SyntaxError | Python代码非法,代码不能编译,通常是语法错误 |
TypeError | 传入对象类型与要求的类型不符 |
UnboundLocalError | 试图访问一个还未被设置的局部变量,由于存在同名的全局变量导致混淆 |
ValueError | 传入一个调用者不期望的值,即使值的类型是正确的 |
为了保证程序的健壮性和可读性,必须对异常进行处理
if-else循环语句同样可以进行异常处理,但往往异常是未知的、复杂的,使用try-except则更为合理
try:
被检测的代码块
except 异常类型:
try中一旦检测到异常,就执行这个位置的逻辑
else:
如果没发生错误,自动执行else语句
finally:
有finally语句,则一定会被执行(可以没有)
try...except可以跨越多层调用捕获到错误,如果在一个函数中调用其他函数,其他函数又调用另外的函数,即使这个另外的函数出错,依然可以捕获到并处理。不需要在每个可能出错的地方去捕获错误,只需要在合适的层次写好try...except即可。
出错的时候,一定要分析错误的调用栈信息,才定位错误的位置。
1.多分支结构
可能出现不同异常,对于不同异常进行不同的处理
s1 = 'hello'
try:
int(s1)
except IndexError as e:
print(e)
except KeyError as e:
print(e)
except ValueError as e:
print(e)
except Exception as e: # Exception则为万能异常
print(e)
2.其他结构
s1 = 'hello'
try:
int(s1)
except IndexError as e:
print(e)
except KeyError as e:
print(e)
except ValueError as e:
print(e)
#except Exception as e:
# print(e)
else:
print('try内代码块没有异常则执行我')
finally:
print('无论异常与否,都会执行该模块,通常是进行清理工作')
3.自定义异常
Python所有错误都是从BaseException类派生的,常见的错误类型和继承关系有:
Built-in Exceptions — Python 3.11.4 documentation
class EgonException(BaseException): # 必须继承BaseException类
def __init__(self,msg):
self.msg=msg
try:
raise EgonException('类型错误') # 主动触发异常
except EgonException as e:
print(e)
只有在有必要的时候才定义我们自己的错误类型。如果可以选择Python已有的内置错误类型,尽量使用Python内置的错误类型。
raise语句如果不带参数,就会把当前错误原样抛出。在except中raise一个Error,可以把一种类型的错误转化为另一种类型(只要是合理的转换逻辑)。
try:
10 / 0
except ZeroDivisionError:
raise ValueError('input error!')
4.断言
语法:assert condition, message
- condition是需要检查的条件,如果条件为假,则引发AssertionError异常;
- message是可选的错误消息,用于在断言失败时提供更具体的说明
断言可用于验证代码中的假设和预期条件是否满足。通过在关键位置插入断言语句,可以快速检测到错误并确定错误的原因
需要注意的是,断言语句在生产环境中通常应该被禁用,因为它们会增加运行时的开销。可以通过设置Python解释器的优化级别来禁用断言。也可以通过在启动Python解释器时用-O(大写字母O,不是数字0)参数来关闭assert,关闭后,所有的assert语句都当作pass。
在开发和调试阶段,可以启用断言来帮助捕获和修复问题,而在生产环境中应该关闭断言以提高性能
总结
try-except
- 把错误处理和真正的工作分开来
- 代码更易组织,更清晰,复杂的工作任务更容易实现
- 毫无疑问,更安全了,不至于由于一些小的疏忽而使程序意外崩溃了
异常处理是保底的,只是在错误发生的条件无法预知时,才应该使用,过多的异常处理也会增加开销,降低代码可读性