1.异常介绍
1.1 语法错误(Error)
代码写错了,程序根本跑不起来。
# 语法错误,少了冒号 if 5>3 print("ok")常见语法错误:
SyntaxError、缩进错误IndentationError语法错误必须改代码,无法用异常捕获处理。
1.2 异常(Exception)
代码语法没问题,运行的时候才出错,程序崩溃停止。
num = int("abc") # ValueError print(10 / 0) # ZeroDivisionError异常可以被捕获,让程序不崩溃。
1.3 Python 中异常类的继承关系
每一个异常属于一个类 顶级异常父类为BaseException
所有的异常都继承自Exception 而 Exception又继承自BaseException
BaseException(所有异常的根) ├── Exception(绝大多数“常规错误/异常”的父类) │ ├── SyntaxError(语法错误) │ ├── ZeroDivisionError(除零) │ ├── IndexError(索引越界) │ ├── KeyError(字典键不存在) │ └── ... ├── SystemExit(程序退出信号) └── KeyboardInterrupt(用户按 Ctrl+C 中断)
2. 异常的处理
我们所谓的处理异常 并不是杜绝异常 或者避免异常 而是当程序运行的时候,出现错误的时候提供解决方案,不中断程序,可以让程序继续执行。
3.try-except处理异常
语法:
try: # 有可能出错的代码 代码块 except 异常类型 as e: # 给异常起名e # 出错之后执行的代码 处理代码
""" 案例分析:观察代码中有可能出现几种异常 ,分别是什么? 1.ValueError: invalid literal for int() with base 10: 'abc' 2.ZeroDivisionError: division by zero """ num1 = int(input("请输入被除数\n")) num2 = int(input("请输入除数\n")) print(num1 / num2) print("程序结束")""" 使用try-except处理异常 try结构里书写可能出现异常的代码,try不能单独使用 必须结合 except使用 except用于捕获异常 表示出现了对应的异常 将执行except结构内的代码 如果没有捕捉到 或者没有出现对应的异常 就不会执行对应except结构内的代码 """ try: num1=int(input("请输入被除数:\n")) num2=int(input("请输入除数:\n")) print(num1/num2) except ValueError as e: print(f"第一个except 捕捉到了异常{e}") except ZeroDivisionError as e: print(f"第一个except 捕捉到了异常{e}") print("程序结束") 3.1 捕获多个不同异常
方式 1:分开写多个 except
try: num1=int(input("请输入被除数:\n")) num2=int(input("请输入除数:\n")) print(num1/num2) except ValueError as e: print(f"第一个except 捕捉到了异常{e}") except ZeroDivisionError as e: print(f"第一个except 捕捉到了异常{e}") print("程序结束") 方式 2:一次捕获多个异常(元组)
""" Python支持多个异常书写在一个except中 以简化代码编写 将多个异常书写在一个元组中 """ try: num1 = int(input("请输入被除数\n")) num2 = int(input("请输入除数\n")) print(num1 / num2) except (ValueError,ZeroDivisionError) as e: print(f"捕获到了异常{e}") print("程序结束") Exception可以捕获绝大部分运行时异常
try: 10 / 0 except Exception as e: print("发生异常:", e)⚠️ 开发规范:尽量捕获具体异常类型,少直接捕获 Exception,提高代码可读性
4.try-except-else处理异常
else:try中的代码执行没有出现异常 将会执行的代码 可以提高可读性,即只要看到else中的代码执行了 就说明try中的代码是没报错的
""" try-except-else处理异常 else不能单独使用 必须结合 try-except使用 else:try中的代码执行没有出现异常 将会执行的代码 可以提高可读性, 即只要看到else中的代码执行了 就说明try中的代码是没报错的 """ try: num1 = int(input("请输入被除数\n")) num2 = int(input("请输入除数\n")) result = num1 / num2 except (ZeroDivisionError,ValueError) as e: print(e) else: print(f"{num1} / {num2} = {result}") print("程序结束")5.finally处理异常
finally关键字:用于在try-except之后 表示不管是否出现异常 以及异常是否被捕获到 都将执行的代码
""" 使用finally关闭IO资源 """ try: reader = open("a.txt", "w") print(reader.write("666")) print(10 / 0) except IOError as e: print(e) finally: print("reader对象被关闭了") reader.close()通常用于执行一些必须要进行的清理操作,例如关闭文件、释放资源(如网络连接、数据库连接、锁等)
6. raise抛出异常
raise可以手动制造一个异常,强制报错
""" raise关键字抛出异常 在有些情况下 我们希望程序中的某些错误 直接停止程序 可以使用raise """ def add(a,b): if isinstance(a,(int,float)) and isinstance(b,(int,float)): return a+b else: # 手动抛出异常 会让程序停止 raise TypeError("类型错误,必须为int或者float类型") try: print(add(1,2)) print(add("1",2)) except TypeError as e: print(e) print("程序结束")7.assert(断言)处理异常
7.1 介绍和使用
assert叫做断言,用来检查一个条件是否为 True。
如果条件为
True→ 什么都不发生,代码继续执行如果条件为
False→ 自动抛出AssertionError异常,程序终止
语法:
assert 条件表达式, 错误提示信息
错误提示信息可以省略
""" assert 断言 关键字后边加上一个布尔结果的表达式 如果表达式不成立则会自动创建一个异常对象 AssertionError 类型 如果表达式成立 则不会创建对象 """ def add(a,b): assert isinstance(a,(int,float)) and isinstance(b,(int,float)),"参数类型错误,必须为int或者float" return a+b try: print(add(1,2)) print(add("1",2)) except TypeError as e: print(e) print("程序结束")""" 使用多个assert关键字来处理异常 """ def add(a,b): assert isinstance(a,(int,float)),"第一个参数类型错误,必须为int或者float" assert isinstance(b,(int,float)),"第二个参数类型错误,必须为int或者float" return a+b try: print(add(1,2)) print(add("1",2)) except TypeError as e: print(e) print("程序结束")7.2 关键大坑!⚠️ assert 可以被关闭
Python 运行时可以加参数禁用所有 assert
python -O test.py大写的
-O(优化模式)开启之后:所有 assert 语句直接被删掉,不会执行!👉 所以:绝对不要用 assert 来校验用户输入、业务数据!!
错误示范(千万别这样写)
# 危险!-O运行时断言失效,负数直接放行 def set_age(age): assert age>0, "年龄不能<=0" print(age)正确做法:业务校验用 if + raise
def set_age(age): if age <= 0: raise ValueError("年龄不能<=0") print(age)
7.4 assert的用途
✅推荐用途(开发调试阶段)
检查程序内部逻辑是否正确(自检)
验证函数返回值是否符合预期
单元测试、调试代码,快速定位 bug
❌禁止用途
用户输入校验
API 参数校验
业务规则校验(生产环境不能依赖它)
assert 是调试工具,用来开发阶段做内部自检;生产环境可被关闭,不能当做正式的参数校验手段。
8. 自定义异常
继承
Exception父类,就可以做自定义异常
""" 自定义异常:当Python提供的异常不能满足我们的开发需求时 我们就需要自定义异常 """ # 编写类继承异常父类即可 class InputAgeError(Exception): pass class Student: def __init__(self,age): self.age = age @property def age(self): return self.__age @age.setter def age(self,age): if 0<=age<=120: self.__age = age else: raise InputAgeError(f"年龄赋值错误:{age},必须在1~120之间") pass s1=Student(150)9.异常的传递
""" 异常的传递 如果存在多层try-except嵌套 最内层的try中出现了异常 先由最内层的except来尝试捕获 如果捕获到了 整个嵌套的try-except结构结束 如果捕获不到 则层层向外传递 直到捕获到 或者 整个嵌套try-except结束 """ try: try: try: print(1/0) except NameError as e: print(e) except ZeroDivisionError as e: print(e) except Exception as e: print(e)
10.with关键字处理异常
""" 使用with关键字 简化try-finally的书写 从而更加简洁的管理资源 """ try: with open ('test.txt','w') as f: print(f.write("ttc")) finally: print(f.closed) # True 表示已经自动关闭了