异常(异常是python对象) 和 自定义异常类
Python提供了异常和断言来处理程序在运行过程中出现的异常和错误
什么是异常?
分清楚程序发生异常和程序执行错误,它们完全是两码事,
程序由于错误导致的运行异常,是需要程序员想办法解决的;
但还有一些异常,是程序正常运行的结果,比如用 raise 手动引发的异常。
异常是在程序执行过程中发生的影响程序正常执行的一个事件。
当Python检测到一个错误时,解释器就会指出当前流已无法继续执行下去,这时候就出现了异常。
**异常是指因为程序出错而在正常控制流以外采取的行为。 **
(原来异常的设计是一个有用的东西,有了异常之后程序出错就会终止,而不会出现正常控制流以外采取的行动)
异常是Python对象,当Python无法正常处理程序时就会抛出一个异常。
(看柳青老师ppt中有 BaseException
是所有异常的基类,而Exception
是常规错误的基类,所以python中的很多异常都是BaseException
的派生类)
一旦Python脚本发生异常,程序需要捕获并处理它,否则程序会终止执行。
异常处理使程序能够处理完异常后继续它的正常执行,不至于使程序因异常导致退出或崩溃。
语法错误和逻辑错误不属于异常,但有些语法错误往往会导致异常,例如由于大小写拼写错误而访问不存在的对象。
异常分为两个阶段:
- 第一个阶段是引起异常发生的错误;
- 第二个阶段是检测并处理阶段。
当程序出现错误,python会自动引发异常,也可以通过raise显式地引发异常。
python中的标准异常
Python异常体系结构如下图:
常见的异常如下表所示:
异常名称 | 描述 |
---|---|
BaseException | 所有异常的基类 |
SystemExit | 解释器请求退出 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
Exception | 常规错误的基类 |
StopIteration | 迭代器没有更多的值 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
WindowsError | 系统调用失败 |
ImportError | 导入模块/对象失败 |
LookupError | 无效数据查询的基类 |
IndexError | 序列中没有此索引(index) |
KeyError | 映射中没有这个键 |
MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
NameError | 未声明/初始化对象 (没有属性) |
UnboundLocalError | 访问未初始化的本地变量 |
ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
NotImplementedError | 尚未实现的方法 |
SyntaxError | Python 语法错误 |
IndentationError | 缩进错误 |
TabError | Tab 和空格混用 |
SystemError | 一般的解释器系统错误 |
TypeError | 对类型无效的操作 |
ValueErrorv | 传入无效的参数 |
UnicodeError | Unicode 相关的错误 |
UnicodeDecodeError | Unicode 解码时的错误 |
UnicodeEncodeError | Unicode 编码时错误 |
UnicodeTranslateError | Unicode 转换时错误 |
Warning | 警告的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
FutureWarning | 关于构造将来语义会有改变的警告 |
OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
PendingDeprecationWarning | 关于特性将会被废弃的警告 |
RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
SyntaxWarning | 可疑的语法的警告 |
UserWarning | 用户代码生成的警告 |
注意,BaseException是异常的顶级类。但是这个类不能当作是由用户定义的类直接继承的,而是要继承Exception。Exception类是与应用相关的异常的顶层根超类,除了系统退出事件类之外(SystemExit、KeyboardInterrupt和GeneratorExit),几乎所有的用户定义的类都应该继承自这个类,而不是BaseException
捕获与处理异常
try:
<可能出现异常的语句块>
except <异常类名字name1>:
<异常处理语句块1>
#如果在try部份引发了'name1'异常,执行这部分语句
except <异常类名字name2>,<数据>:
<异常处理语句块2>
#如果引发了'name2'异常,获得附加的数据
…
except:
<异常处理语句块n>
#如果引发了异常,但与上述异常都不匹配,执行此语句块
else:
<else语句块>
#如果没有上述所列的异常发生,执行else语句块
finally:
<始终执行的语句块>
try/except
语句用来检测try语句块中的异常,让except语句捕获异常信息并处理。
如果不想在异常发生时结束程序,只需要在try里捕获它,并在except中处理捕获到的异常。
try中的语句块先执行。
如果try语句块中的某一语句执行时发生异常,Python就跳到except部分,
从上到下判断抛出的异常对象是否与except后面的异常类相匹配,并执行第一个匹配该异常的except后面的语句块,异常处理完毕。
如果异常发生了,但是没有找到匹配的异常类别,则执行不带任何匹配类型的except语句后面的语句块,异常处理完毕。
示例代码
try:
#正常执行的代码
pass
except <错误1>:
#抛出错误1时执行的代码
pass
except <错误2>:
#抛出错误2时执行的代码
pass
except <错误3, 错误4>:
#抛出错误3或者错误4时执行的代码
pass
except Exception as result:
print("未知错误类型:{}".format(result))
else:
#没有异常才会执行的代码
pass
finally:
#无论是否有异常都会执行的代码
print("程序结束")
异常的传递
当函数/方法执行出现异常会将异常传递给函数/方法的调用一方
如果传递到主程序,仍然没有异常处理程序才会被终止
注意:
在开发中,可以在主函数中增加异常捕获,这样在主函数中调用的其他函数,只要出现异常,都会传递到主函数的异常捕获中
这样就不需要在代码中,增加大量的异常捕获能够保证代码的整洁
示例
def demo1():
return int(input("请输入一个整数:"))
def demo2():
return demo1()
def main():
try:
print(demo2())
except ValueError:
print("请输入正确的整数")
except Exception as result:
print("未知错误 %s" % result)
main()
自定义异常类
仅仅使用标准模块中的异常类通常不能满足系统开发的需要
有时候需要自定义一些异常类
系统无法识别自定义的异常类,只能在程序中显式地使用raise抛出异常
可以通过扩展BaseException类或其子类来创建自定义异常类
BaseException
是所有异常的基类
raise的作用
raise 语句的基本语法格式为:raise [exceptionName [(reason)]]
其中,用 [] 括起来的为可选参数,其作用是指定抛出的异常名称,以及异常信息的相关描述。如果可选参数全部省略,则 raise 会把当前错误原样抛出;如果仅省略 (reason),则在抛出异常时,将不附带任何的异常描述信息。
也就是说,raise 语句有如下三种常用的用法:
- raise:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。
- raise 异常类名称:raise 后带一个异常类名称,表示引发执行类型的异常。
- raise 异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。
示例如下
>>> raise
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
raise
RuntimeError: No active exception to reraise
>>> raise ZeroDivisionError
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
raise ZeroDivisionError
ZeroDivisionError
>>> raise ZeroDivisionError("除数不能为零")
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
raise ZeroDivisionError("除数不能为零")
ZeroDivisionError: 除数不能为零
需要注意的是,就算是直接raise也会触发异常RuntimeError
理解异常是一个类
通过一个例子来体会
>>> class ShortInputError(Exception):
... def __init__ (self,length,atleast):
... Exception.__init__(self)
... self.length = length
... self.atleast = atleast
...
>>> try:
... s = "123456"
... if len(s) <10:
... raise ShortInputError(len(s),10)
... except ShortInputError as result:
... print("长度至少是{}".format(result.atleast))
... else:
... print("没有异常")
...
长度至少是10
从这个例子很容易看出来,其中ShortInputError是一个派生类,基类是Exception,在这个例子中,如果s的长度小于10,就会抛出ShortInputError,然后异常就会被try捕获,然后通过except匹配,如果匹配上的话,输出带有具体信息的异常
断言与上下文管理
断言与上下文管理是两种比较特殊的异常处理方式,在形式上比异常处理结构要简单一些。
断言是申明表达式为真的判定。如果表达式为假则抛出异常。
断言语句可以理解为raise-if-not语句,用来测试表示式,如果返回值为假,则触发异常。
如果断言成功,则程序不采取任何措施,否则触发AssertionError异常。
断言的语法格式如下:
assert expression [, arguments]
注意一下三条命令就可以明白assert
的作用
>>> assert 1+1 ==2
>>> assert 1+1 !=2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
>>> assert 1+1 !=2,"错误"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: 错误
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本