python快速入门学习笔记(进阶篇)二十二:错误与异常

  • 原创
  • 作者:程序员三丰
  • 发布时间:2026-04-22 17:09
  • 浏览量:3
python入门第二十二课,主要是学习了错误与异常,异常处理是程序健壮性的保障,通过捕获并处理运行时错误,实现错误与正常逻辑的分离,避免程序意外崩溃。

理解什么是错误与异常

错误

错误是指:代码本身有语法错误,解释器无法执行代码。—— 无法通过异常处理机制解决。

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

多个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 ****

一个 except 捕获不同的异常

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}')
声明:本文为原创文章,51blog.xyz和作者拥有版权,如需转载,请注明来源于51blog.xyz并保留原文链接:https://www.51blog.xyz/article/124.html

文章归档

推荐文章

buildadmin logo
Thinkphp8 Vue3 Element PLus TypeScript Vite Pinia

🔥BuildAdmin是一个永久免费开源,无需授权即可商业使用,且使用了流行技术栈快速创建商业级后台管理系统。

热门标签

PHP ThinkPHP ThinkPHP5.1 Go Mysql Mysql5.7 Redis Linux CentOS7 Git HTML CSS CSS3 Javascript JQuery Vue LayUI VMware Uniapp 微信小程序 docker wiki Confluence7 学习笔记 uView ES6 Ant Design Pro of Vue React ThinkPHP6.0 chrome 扩展 翻译工具 Nuxt SSR 服务端渲染 scrollreveal.js ThinkPHP8.0 Mac webman 跨域CORS vscode GitHub ECharts Canvas vue3 three.js 微信支付 PHP全栈开发 Python AI 人工智能 AI生成 工作经验 实战笔记