【Python与AI基础】Python编程基础:异常处理
一、异常类型
1、内置异常
Python的异常处理能力是很强大的,它有很多内置异常,可向用户准确反馈出错信息。在Python中,异常也是对象,可对它进行操作。BaseException是所有内置异常的基类,但用户定义的类并不直接继承BaseException,所有的异常类都是从Exception继承,且都在exceptions模块中定义。Python自动将所有异常名称放在内建命名空间中,所以程序不必导入exceptions模块即可使用异常。一旦引发而且没有捕捉SystemExit异常,程序执行就会终止。如果交互式会话遇到一个未被捕捉的SystemExit异常,会话就会终止。
内置异常类的层次结构如下:
BaseException # 所有异常的基类
+-- SystemExit # 解释器请求退出
+-- KeyboardInterrupt # 用户中断执行(通常是输入^C)
+-- GeneratorExit # 生成器(generator)发生异常来通知退出
+-- Exception # 常规异常的基类
+-- StopIteration # 迭代器没有更多的值
+-- StopAsyncIteration # 必须通过异步迭代器对象的__anext__()方法引发以停止迭代
+-- ArithmeticError # 各种算术错误引发的内置异常的基类
| +-- FloatingPointError # 浮点计算错误
| +-- OverflowError # 数值运算结果太大无法表示
| +-- ZeroDivisionError # 除(或取模)零 (所有数据类型)
+-- AssertionError # 当assert语句失败时引发
+-- AttributeError # 属性引用或赋值失败
+-- BufferError # 无法执行与缓冲区相关的操作时引发
+-- EOFError # 当input()函数在没有读取任何数据的情况下达到文件结束条件(EOF)时引发
+-- ImportError # 导入模块/对象失败
| +-- ModuleNotFoundError # 无法找到模块或在在sys.modules中找到None
+-- LookupError # 映射或序列上使用的键或索引无效时引发的异常的基类
| +-- IndexError # 序列中没有此索引(index)
| +-- KeyError # 映射中没有这个键
+-- MemoryError # 内存溢出错误(对于Python 解释器不是致命的)
+-- NameError # 未声明/初始化对象 (没有属性)
| +-- UnboundLocalError # 访问未初始化的本地变量
+-- OSError # 操作系统错误,EnvironmentError,IOError,WindowsError,socket.error,select.error和mmap.error已合并到OSError中,构造函数可能返回子类
| +-- BlockingIOError # 操作将阻塞对象(e.g. socket)设置为非阻塞操作
| +-- ChildProcessError # 在子进程上的操作失败
| +-- ConnectionError # 与连接相关的异常的基类
| | +-- BrokenPipeError # 另一端关闭时尝试写入管道或试图在已关闭写入的套接字上写入
| | +-- ConnectionAbortedError # 连接尝试被对等方中止
| | +-- ConnectionRefusedError # 连接尝试被对等方拒绝
| | +-- ConnectionResetError # 连接由对等方重置
| +-- FileExistsError # 创建已存在的文件或目录
| +-- FileNotFoundError # 请求不存在的文件或目录
| +-- InterruptedError # 系统调用被输入信号中断
| +-- IsADirectoryError # 在目录上请求文件操作(例如 os.remove())
| +-- NotADirectoryError # 在不是目录的事物上请求目录操作(例如 os.listdir())
| +-- PermissionError # 尝试在没有足够访问权限的情况下运行操作
| +-- ProcessLookupError # 给定进程不存在
| +-- TimeoutError # 系统函数在系统级别超时
+-- ReferenceError # weakref.proxy()函数创建的弱引用试图访问已经垃圾回收了的对象
+-- RuntimeError # 在检测到不属于任何其他类别的错误时触发
| +-- NotImplementedError # 在用户定义的基类中,抽象方法要求派生类重写该方法或者正在开发的类指示仍然需要添加实际实现
| +-- RecursionError # 解释器检测到超出最大递归深度
+-- SyntaxError # Python 语法错误
| +-- IndentationError # 缩进错误
| +-- TabError # Tab和空格混用
+-- SystemError # 解释器发现内部错误
+-- TypeError # 操作或函数应用于不适当类型的对象
+-- ValueError # 操作或函数接收到具有正确类型但值不合适的参数
| +-- UnicodeError # 发生与Unicode相关的编码或解码错误
| +-- UnicodeDecodeError # Unicode解码错误
| +-- UnicodeEncodeError # Unicode编码错误
| +-- UnicodeTranslateError # Unicode转码错误
+-- Warning # 警告的基类
+-- DeprecationWarning # 有关已弃用功能的警告的基类
+-- PendingDeprecationWarning # 有关不推荐使用功能的警告的基类
+-- RuntimeWarning # 有关可疑的运行时行为的警告的基类
+-- SyntaxWarning # 关于可疑语法警告的基类
+-- UserWarning # 用户代码生成警告的基类
+-- FutureWarning # 有关已弃用功能的警告的基类
+-- ImportWarning # 关于模块导入时可能出错的警告的基类
+-- UnicodeWarning # 与Unicode相关的警告的基类
+-- BytesWarning # 与bytes和bytearray相关的警告的基类
+-- ResourceWarning # 与资源使用相关的警告的基类。被默认警告过滤器忽略。
2、自定义异常
通过关键字raise实现自定义异常
def get_name(name):
if not name:
raise Exception('parameter error') # 如果参数为空字符串,0等值,则抛出异常
else:
print(f'姓名:{name}')
二、异常处理
当发生异常时,我们就需要对异常进行捕获,然后进行相应的处理。python的异常捕获常用try…except…结构,把可能发生错误的语句放在try模块里,用except来处理异常,每一个try,都必须至少对应一个except。此外,与python异常相关的关键字主要有:
1、try:
将有可能引发异常的语句放在try中
2、except
- 捕获异常,并且针对该异常进行相应的处理,可以同时存在多个except语句
- except 异常,捕获1个指定异常
- except (异常1,异常2,…),捕获元组中的异常
- except Exception,捕获所有异常
3、例一:多个except语句捕获不同的异常
li = [1,2,3,4]
try:
print(li[0])
print(li[1]/0) # 除0
except IndexError:
print('索引超出范围')
except ZeroDivisionError:
print('不能除以0')
'''
运行结果:
不能除以0
'''
4、例2:一个except语句捕获多个异常
li = [1,2,3,4]
try:
print(li[10]) # 索引超出范围
print(li[1]/0) # 除0
except (IndexError,ZeroDivisionError) as e:
print(e)
'''
运行结果:
list index out of range
'''
5、例3:使用Exception捕获所有异常
li = [1,2,3,4]
try:
print(li[10]) # 索引超出范围
print(li[1]/0) # 除0
except Exception as e:
print(e)
'''
运行结果:
list index out of range
'''
6、例4:判断数字是否合法
m = input('转账金额:')
try:
m = float(m)
except Exception as e:
print('转账金额输入错误')
7、else
如果try中的语句没有引发异常,则执行else的代码
li = [1,2,3,4]
try:
print(li[10]) # 索引超出范围
print(li[1]/0) # 除0
except Exception as e:
print(e)
else:
print(li)
8、finally
无论try语句中的代码是否引发异常,都要执行finally中的代码
li = [1,2,3,4]
try:
print(li[10]) # 索引超出范围
print(li[1]/0) # 除0
except Exception as e:
print(e)
else:
li.append(5)
finally:
print(li)
三、代码实例
下述代码演示了在建立与MySQL的连接并执行SQL语句时,可能出现的一些异常以及捕获和处理方式。
try:
conn = pymysql.connect(host='localhost', user='root', password='1234567', database='learn', charset='utf8')
cursor = conn.cursor()
cursor.execute("select * from user")
a = 1/0
except pymysql.err.OperationalError as e:
# print(e)
print("数据库连接不正确.")
except pymysql.err.ProgrammingError as e:
print("SQL语句不正确.")
except ZeroDivisionError as e:
print("除数不能为零.")
except Exception as e:
print("代码还存在其他异常.")
finally:
conn.close() # 此行代码可能也会抛出异常,比如数据库连接不成功时,则可以继续在finally中使用try...except捕获
print("数据库连接关闭")
连接Socket
try:
s = socket.socket()
s.connect(('192.168.112.187', 8088))
print(s.__str__())
except TypeError as e:
print(f"Socket未正常实例化: {e}")
except ConnectionRefusedError as e:
print(f"没有正常连接到服务器: {e}")
except Exception as e:
print(f"代码出现未知异常: {e}")
finally:
s.close()
主动抛出异常:
# 主动抛出异常,通常在封装函数或方法时使用
raise TypeError("这是主动抛出的异常")
raise Exception("这是主动抛出的异常")