8.Python 异常 (Exception)

1. Python 中的错误

在 Python 开发过程中,可能会遇到 3 种错误:

  1. 语法错误 (Syntax Error) :代码不符合 Python 语法规则。

    • PyCharm 会给出红色的波浪线提示,运行会出现 SyntaxError
    python 复制代码
    # 计算 a 跟 b 的和
    a = 10
    b = 5
    print(a - b)  # 5 
  2. 逻辑错误 (Logic Error、Bug) :代码不符合业务逻辑。

    • PyCharm 不会给出任何提示信息。
  3. 异常 (Exception) :操作不合理、Python 无法正常处理你的代码。

    • Python 会抛出异常信息(比如 XxxError)。
    python 复制代码
    i = int('小码哥')
    print(i)
    
    print(10 / 0)

2. 异常的特点

  • 会直接导致程序终止运行
python 复制代码
print(1)
print(10 / 0)
print(2)

def test():
    print(2)
    print(10 / 0)
    print(3)

print(1)
test()
print(4)

# 运行结果:
# 1
# ZeroDivisionError: division by zero
# 1
# 2
# ZeroDivisionError: division by zero
  • 有时候来得猝不及防,把握不住
python 复制代码
age = int(input('请输入你的年龄:'))
print(age)

3. 异常的处理

在绝大部分情况下:

  • 我们都不希望程序因为异常而终止运行。
  • 我们更希望的是:
    • 能够"把握住"异常
    • 能够拦截(捕获)异常
    • 根据不同的异常信息作出不同的处理
    • 让程序保持正常运行

3.1 捕获异常的基本结构

tryexceptelsefinally 配合使用:

  • try :包含可能会产生异常的代码。
    • 一旦出现异常,会直接跳过 try 中剩余未执行的代码。
  • except :当出现异常时,会执行 except 中的代码。
    • 可以省略。
  • else :当没有出现异常时,会执行 else 中的代码。
    • 可以省略。只能在有 except 时使用
  • finally :不管是否出现异常,最终都会执行 finally 中的代码。
    • 可以省略。
python 复制代码
try:
    代码1
except:
    代码2
else:
    代码3
finally:
    代码4

综合示例:

python 复制代码
try:
    a = int(input('请输入第1个整数:'))
    print(1)
    b = int(input('请输入第2个整数:'))
    print(2)
    print(f'a除以b等于{a / b}')
    print(3)
except ValueError:
    print('输入的数据无法转成整数')
except ZeroDivisionError:
    print('0不能作为被除数')
else:
    print('很好,一切正常')
finally:
    print('操作处理完毕')
print(4)

3.2 常见的内置异常类型

  1. ZeroDivisionError :0 作为除数

    python 复制代码
    print(10 / 0) # ZeroDivisionError: division by zero
  2. IndexError :索引超出正常范围

    python 复制代码
    s = [11, 22, 33]
    print(s[5]) # IndexError: list index out of range
  3. NameError :无法找到名称(标识符)

    python 复制代码
    print(age) # NameError: name 'age' is not defined
  4. KeyError :无法找到字典的 key

    python 复制代码
    d = {'age': 18}
    print(d['name']) # KeyError: 'name'
  5. TypeError :使用了不恰当类型的对象

    python 复制代码
    print('age is ' + 18) # TypeError: can only concatenate str (not "int") to str
  6. ValueError :虽然类型正确,但值不正确

    python 复制代码
    n = int('娃哈哈') # ValueError: invalid literal for int() with base 10: '娃哈哈'
  7. AttributeError :操作(访问、赋值等)属性失败

    python 复制代码
    class Person:
        pass
        
    p = Person()
    print(p.age) # AttributeError: 'Person' object has no attribute 'age'

3.3 except 的高级用法

  • 省略异常类型except 后面可以不写异常类型,表示支持所有的异常类型。
python 复制代码
try:
    a = int(input('请输入第1个整数:'))
    b = int(input('请输入第2个整数:'))
    print(f'a除以b等于{a / b}')
    print([][10])
except ValueError:
    print('输入的数据无法转成整数')
except ZeroDivisionError:
    print('0不能作为被除数')
except:
    print('其他异常')
  • 捕获多个异常类型 :可以用元组同时表示多个异常类型。
python 复制代码
try:
    a = int(input('请输入第1个整数:'))
    b = int(input('请输入第2个整数:'))
    print(f'a除以b等于{a / b}')
except (ValueError, ZeroDivisionError):
    print('出现异常')
  • 接收异常对象 :可以用变量来接收异常对象(使用关键字 as)。
python 复制代码
try:
    n = int(input('请输入第1个整数:'))
    print(n)
except BaseException as e:
    print('出现异常', e)

try:
    a = int(input('请输入第1个整数:'))
    b = int(input('请输入第2个整数:'))
    print(f'a除以b等于{a / b}')
except (ValueError, ZeroDivisionError) as e:
    print('出现异常', e)

4. 异常的传播

  • 一旦函数/方法中的代码出现了异常:
    • 会直接跳过剩余的代码,函数/方法停止运行。
    • 函数/方法中产生的异常,会向外传播到当初调用函数/方法的地方。
  • 从异常的打印信息(Traceback),可以很清晰地看出异常的传播轨迹。
  • 异常会由内往外 传播出去,直到被拦截捕获或传播到全局作用域为止。
    • 可以想象成是在寻求帮助,看看哪位大神能够收了(处理)这个异常。
    • 当异常传播到全局作用域时,还没有被拦截捕获,就会导致程序终止运行,并将异常信息打印出来。

5. 抛出异常 (raise)

如果函数/方法的参数有问题,我们可以在函数/方法内部:

  1. 将不合理的值过滤掉。
  2. 抛出异常,告诉传递参数的人:你传递的参数有严重问题。

可以通过 raise 主动抛出异常:

  • raise 后面跟上的必须是异常类型(BaseException 类型或其子类类型)。
python 复制代码
class Person:
    def __init__(self):
        self.__age = 1
        
    @property
    def age(self):
        return self.__age
        
    @age.setter
    def age(self, age):
        if age < 1:  # 主动抛出异常
            raise ValueError('age不能小于1')
        if age > 120:  # 主动抛出异常
            raise ValueError('age不能大于120')
        self.__age = age

try:
    p = Person()
    p.age = -10
    print(p.age)
except ValueError as e:
    print('出现了异常', e.args[0])

6. 自定义异常

为了让异常的类型、描述信息更加精准,可以考虑自定义异常。

  • 一般建议 :自定义的异常类型,最终要继承自 Exception,而并不是 BaseException
python 复制代码
class AgeError(Exception):
    """自定义的异常类型,表示age有问题"""
    def __str__(self):
        return f'{self.args[0]}:{self.args[1]}值不合理'

class Person:
    def __init__(self):
        self.__age = 1
        
    @property
    def age(self):
        return self.__age
        
    @age.setter
    def age(self, age):
        if age < 1:  # 主动抛出异常
            raise AgeError('age不能小于1', age)
        if age > 120:  # 主动抛出异常
            raise AgeError('age不能大于120', age)
        self.__age = age

try:
    p = Person()
    p.age = 300
    print(p.age)
except AgeError as e:
    print('出现了异常', e)
相关推荐
2601_9548118210 分钟前
AI科学实验室MHS标准解读:AI智能体如何统一控制实验室设备接口
人工智能·python
一位正在转型AI全栈的前端工程师10 分钟前
AI 全栈学习之旅 -Week 9:什么是AI Agent?从Function Calling到LangGraph
前端·python
用户03321266636713 分钟前
使用 Python 为 PowerPoint 设置背景色和背景图【附代码示例】
python
ever_up97328 分钟前
LangChain基础知识概述1
人工智能·python·langchain
asdzx671 小时前
Python 实现 PDF 文本查找与高亮标注
开发语言·python·pdf
zander2581 小时前
LeetCode 1143. 最长公共子序列
开发语言·python·算法
轩情吖2 小时前
Python基础知识点完整总结
python·字符串·编程语言·函数·列表·元组·字典
青 春 记 忆2 小时前
零基础入门python69:为 FastAPI 项目构建可复现 Docker 镜像
python·fastapi·后端开发
<花开花落>2 小时前
Python 项目迁移到 uv:经验小结与可复用工作流
python·uv
databook2 小时前
正态分布撒谎时:用柯西分布捕捉生活中的“黑天鹅”
python·数据挖掘·数据分析