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)
相关推荐
是大强11 小时前
下载的jar怎么放到本地仓库
python·pycharm·jar
茗创科技11 小时前
Nature Neuroscience | 脑网络架构如何平衡分布式神经回路之间的合作与竞争?
python·神经网络·matlab·脑网络
abc123456sdggfd11 小时前
如何统一SQL视图报错信息_使用异常处理机制包装视图
jvm·数据库·python
qq_4609784011 小时前
如何处理SQL循环逻辑_探索递归CTE实现复杂计算
jvm·数据库·python
码农阿豪11 小时前
Django接金仓数据库:我踩过的坑和填坑指南
数据库·python·django
2401_8314194411 小时前
C++如何利用YAML存储复杂的数学矩阵_Eigen库结合yaml-cpp用法【实战】
jvm·数据库·python
2401_8987176611 小时前
如何进行SQL数学计算_运用ROUND与CEIL处理数值精度
jvm·数据库·python
kishu_iOS&AI11 小时前
NLP —— 文本预处理
人工智能·pytorch·python·自然语言处理
2501_9012005311 小时前
Pytest 实现两级参数化:让服务名依赖于应用名的灵活测试方案
jvm·数据库·python