错误是指:代码本身有语法错误,解释器无法执行代码。—— 无法通过异常处理机制解决。
age = 18
if age >= 18 # 这一行语法错误,运行时会报错:SyntaxError: expected ':'
print('成年人')
代码语法上没有问题,但执行过程中出现了问题。—— 可以通过异常处理机制解决。
下面列举出几种开发中常见的异常类型:
1️⃣ ZeroDivisionError:当除数为 0 时触发。
num1 = 100
num2 = 0
result = num1 / num2
2️⃣ TypeError:当操作的数据类型不正确或不兼容时触发。
result = '10' + 5
3️⃣ AttributeError:当对象没有指定的属性或方法时触发。
# 示例1
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p1 = Person("John", 25)
print(p1.name)
print(p1.age)
# print(p1.gender) # 访问不存在的属性
# 示例2
nums = [1, 2, 3]
# nums.add(5) # 调用不存在的方法
4️⃣ IndexError:当索引超出范围(索引越界)时触发。
nums2 = [1, 2, 3]
print(nums2[3])
5️⃣ NameError:当使用了不存在的变量时触发。
print(nums3)
6️⃣ KeyError:当访问字典中不存在的 key 时触发。
person = {'name': 'John', 'age': 25}
print(person['name'])
print(person['gender'])
7️⃣ ValueError:当值不合法,但类型正确时触发。
int('hello')
Python 中异常类的继承关系(层级关系)可以通过阅读官方文档了解:https://docs.python.org/zh-cn/3.13/library/exceptions.html#exception-hierarchy
BaseException 是所有异常类的父类,Exception 中包含的是开发中常见的业务异常。
程序运行过程中出现的异常,如果得不到处理,那程序就会立即崩溃,导致后续代码无法执行。
异常处理不是让异常消失,而是将异常捕获到,随后根据异常的具体情况,来执行指定的逻辑。
下面是【未进行异常处理】的代码示例:
print('异常代码前的输出')
num_a = 100
num_b = 0
result = num_a / num_b # 这一行存在 ZeroDivisionError
print('异常代码后的输出') # 由于上一行异常未处理,导致这行代码无法执行
核心规则如下:
✅️ 将可能出现异常的代码放在try中,出现异常后的处理代码写在except中。
✅️ 如果try中的代码出现异常,那try中的后续代码不会执行,并自动跳转到except中。
✅️ 如果try中的代码没有异常,那except中的代码就不会执行。
✅️ 无论是否发生异常,try-except后面的代码都会继续执行。
✅️ 直接写except捕获到Python中所有的异常——实际开发中不推荐这样做。
下面是【进行了异常处理】的代码示例:
print('异常代码前的输出')
try:
num_a = 100
num_b = 0
result = num_a / num_b # 这一行存在 ZeroDivisionError
print('异常代码后的输出')
except:
print('抱歉,程序出现了异常')
print('其他后续代码……')
通过except 异常类的语法来捕获指定的类型的异常,多个这样的语句就能捕获多个不同类型的异常。请看下面的示例代码:
print('欢迎使用本程序')
try:
a = int(input('请输入第一个数:'))
b = int(input('请输入第二个数:'))
result = a / b
print(f'{a}除以{b}的结果是:{result}')
except ZeroDivisionError:
print('程序异常:0不能作为除数!')
except ValueError:
print('程序异常:输入的必须是数字!')
print('***** 我是后续的其它逻辑1 ****')
print('***** 我是后续的其它逻辑2 ****')
print(issubclass(ZeroDivisionError, ArithmeticError)) # True
print(issubclass(ZeroDivisionError, Exception)) # True
print(issubclass(ValueError, Exception)) # True
print(issubclass(KeyboardInterrupt, Exception)) # False
print(issubclass(KeyboardInterrupt, BaseException)) # True
多个except从上往下匹配,匹配成功后不再向下匹配。
print('欢迎使用本程序')
try:
a = int(input('请输入第一个数:'))
b = int(input('请输入第二个数:'))
print(x) # 触发 except Exception
result = a / b
print(f'{a}除以{b}的结果是:{result}')
except ZeroDivisionError:
print('程序异常:0不能作为除数!')
except ValueError:
print('程序异常:输入的必须是数字!')
except Exception:
print('程序异常!')
print('***** 我是后续的其它逻辑1 ****')
print('***** 我是后续的其它逻辑2 ****')
通过e变量,可以获取异常相关的信息,也可以借助traceback去格式化异常信息。
print('欢迎使用本程序')
try:
a = int(input('请输入第一个数:'))
b = int(input('请输入第二个数:'))
print(x) # 触发 except Exception
result = a / b
print(f'{a}除以{b}的结果是:{result}')
except ZeroDivisionError:
print('程序异常:0不能作为除数!')
except ValueError:
print('程序异常:输入的必须是数字!')
except Exception as e:
print('程序异常!')
print(f'异常信息:{e}')
print(f'异常类型:{type(e)}')
print(f'异常参数:{e.args}')
print(f'异常的文件:{e.__traceback__.tb_frame.f_code.co_filename}')
print(f'异常的具体行数:{e.__traceback__.tb_lineno}')
# 通过 traceback 来回溯异常
import traceback
print(traceback.format_exc())
print('***** 我是后续的其它逻辑1 ****')
print('***** 我是后续的其它逻辑2 ****')
运行结果:
欢迎使用本程序
请输入第一个数:1
请输入第二个数:1
程序异常!
异常信息:name 'x' is not defined
异常类型:<class 'NameError'>
异常参数:("name 'x' is not defined",)
异常的文件:E:\www.py\basic\advanced\chapter29-exception.py
异常的具体行数:71
Traceback (most recent call last):
File "E:\www.py\basic\advanced\chapter29-exception.py", line 71, in <module>
print(x) # 触发 except Exception
^
NameError: name 'x' is not defined
***** 我是后续的其它逻辑1 ****
***** 我是后续的其它逻辑2 ****
print('欢迎使用本程序')
try:
a = int(input('请输入第一个数:'))
b = int(input('请输入第二个数:'))
# print(x) # 触发 except Exception
result = a / b
print(f'{a}除以{b}的结果是:{result}')
except (ZeroDivisionError, ValueError, Exception) as e:
msg: str = ''
if isinstance(e, ZeroDivisionError):
msg = '0 不能作为除数!'
elif isinstance(e, ValueError):
msg = '输入的必须是数字!'
print(f'程序异常!{msg}')
import traceback
print(traceback.format_exc())
print('***** 我是后续的其它逻辑1 ****')
print('***** 我是后续的其它逻辑2 ****')
1️⃣ try尝试去做可能出现异常的事情。
2️⃣ except出现异常时的处理(出现异常时怎么补救)。
3️⃣ else如果一切顺利(没有出现异常)要做的事情。
4️⃣ finally无论有没有异常,都要做的事情。
print('欢迎使用本程序')
try:
print('try:')
// print(x) # 触发 except Exception
a = int(input('请输入第一个数:'))
b = int(input('请输入第二个数:'))
result = a / b
print(f'\t{a}除以{b}的结果是:{result}')
except (ZeroDivisionError, ValueError, Exception) as e:
print('except:')
if isinstance(e, ZeroDivisionError):
print('\t程序异常,0不能作为除数!')
elif isinstance(e, ValueError):
print('\t程序异常,您输入的必须是数字!')
else:
print(f'\t程序异常:{e}')
else:
print('else:')
print('\t挺好的,try中的代码没有任何异常!')
finally:
print('finally:')
print('\t无论有没有异常,我的计算都结束了!')
print('********* 异常处理模块之后的代码 *********')
当程序遇到不符合预期情况时,可以使用raise语句手动触发(抛出)异常。
print('欢迎使用年龄判断系统')
try:
age = int(input('请输入你的年龄:'))
if 18 <= age <= 120:
print('成年')
elif 0 < age <= 18:
print('未成年')
else:
raise ValueError('年龄应该为0~120的整数')
except Exception as e:
print(f'程序异常:{type(e)} {e}')
如果异常没有被当前代码块所捕获处理,那该异常就会沿着调用链,逐层传递给其调用者。
如果所有调用者,都没有捕获该异常,那最终程序将因【未处理异常】而意外终止。
def test1():
print('****** test1 开始 ******')
result = '100' + 100
print('****** test1 结束 ******')
def test2():
print('****** test2 开始 ******')
try:
test1()
except Exception as e:
print(f'程序异常:{type(e)} {e}')
print('****** test2 结束 ******')
def test3():
print('****** test3 开始 ******')
test2()
print('****** test3 结束 ******')
test3()
上面代码执行结果如下:
****** test3 开始 ******
****** test2 开始 ******
****** test1 开始 ******
程序异常:<class 'TypeError'> can only concatenate str (not "int") to str
****** test2 结束 ******
****** test3 结束 ******
由开发人员自己定义一个异常类,用来表示代码中“更具体、更有业务含义”的异常。
具体规则:定义一个类,类名通常以Error结尾,继承Exception类或它的子类。
class SchoolNameError(Exception):
def __init__(self, msg):
super().__init__('【校名异常】' + msg)
def check_school_name(name):
if len(name) > 10:
raise SchoolNameError('学校名称过长')
else:
print('学校名称合法')
try:
n = input('请输入学校名称:')
check_school_name(n)
except SchoolNameError as e:
print(f'程序异常:{type(e)} {e}')
🔥BuildAdmin是一个永久免费开源,无需授权即可商业使用,且使用了流行技术栈快速创建商业级后台管理系统。