Python高阶:看,那里有个BUG - 异常

1 概述

1.1 背景介绍

Python作为一门广泛应用于编程领域的高级编程语言,以其简洁、易读的语法而闻名。然而,在编写Python程序时,难免会遇到各种各样的错误和异常。为了编写健壮的程序并提高代码的可维护性,了解和正确处理这些错误和异常至关重要。

通过本案例可以帮助我们了解 Python 中错误和异常的产生及处理,了解 Python 中程序遇到异常的处理过程。

1.2 适用对象

  • 个人开发者
  • 高校学生

1.3 案例时间

本案例总时长预计30分钟。

1.4 案例流程

9fd67b06a3a809366e78c96eeba1a887.png{{{width="30%" height="auto"}}}

说明:

① 登录华为云,开通开发者空间,进入云主机,打开CodeArts IDE for Python创建工程; ② 编写代码运行。

1.5 资源总览

本案例预计花费总计0元。

资源名称规格单价(元)时长(分钟)
开发者空间-云主机2vCPUs | 4GB X86 CodeArts IDE for Python免费30

2 准备开发环境

2.1 配置云主机并进入

参考“10分钟玩转云主机” 案例介绍中“2.2 申请云主机”章节内容完成华为开发者空间云主机申请与配置,配置云主机建议:“CPU架构”选择“X86”,“操作系统”选择“Ubuntu”。

3aa838e36238c4c8af0f37b6c94cf76c.png 然后点击“进入桌面”进入云主机。 aef13011857c2efc0323e4dfaf676f9b.png

2.2 使用CodeArts IDE创建工程

参考“初识云主机:CodeArts IDE入门”案例介绍“3.1 新建工程”章节新建工程。

新建的工程包含如下三个目录文件部分:

目录文件说明
.artsCodeArts的配置文件
venv虚拟环境
main.py默认生成的入口文件

68d46cce9998a4909cd7a04f1fa7956f.png

3 异常与程序调试

3.1 Python中的异常

在Python中,异常是指程序中发生的错误或者意外情况,它会导致程序的正常执行流程被中断。Python使用异常处理机制来管理这些错误,使得开发者能够优雅地处理错误情况,而不是让程序因为一个未被捕获的异常而崩溃。

下面练习以帮助我们掌握Python这门编程语言中对于错误处理以及程序调试的相关知识。

3.1.1 代码错误

代码错误通常发生在代码编写时,由于不符合Python的语法规则而导致的错误。例如,遗漏冒号、错误的缩进、拼写错误的关键字等。

代码错误会导致Python解释器无法理解你的代码,因此在尝试运行代码时会立即抛出错误信息,并且通常会指出错误发生的具体位置(例如行号和字符位置)。

代码示例:

# 缩进不规范
def func(): 
pass 
return 0    

e3e39137733e8c8c01cb09a93475b311.png

# 语法错误,没有加“:”
def func() 
pass 
return 0  

0465363353c1deacb9d0b864992995be.png

3.1.2 异常

异常是在程序运行时发生的错误,它们通常是由于某些运行时条件不满足(例如除以零、使用越界下标、试图访问不存在的文件等)而导致的。

当程序遇到异常时,它不会立即终止,而是会抛出一个异常。如果没有被捕获和处理,程序将终止并显示一个错误消息。但如果异常被妥善处理,程序可以继续执行。

代码示例:

# 除数为 0
def func():
 return 1/0
func()

2a9e3c570ce367bc64c30a643ab15e25.png

#下标越界 
l = [1,2]
def func():
 return l[3]
func()

356ea7faa1ff897f157c9525756ef154.png

# 文件不存在 
with open("file.file") as f:
  f.read()

08cc0dfd4123e1ae1dc94cbda9e0a376.png

3.2 异常处理

3.2.1 使用try…except语句来捕获异常

try:包含可能引发异常的代码块。如果在try块中发生任何类型的异常,程序将立即跳转到与之匹配的except块进行处理,在可能抛出异常的代码块,使用try语句进行捕获。

代码示例:

# 对于可能为0的除数,使用try语句捕获异常,并打印出错误提示。
def func(num):
 return 1/num
try:
 num = 0
 func(num)
except ZeroDivisionError as e:
 print("nun 不能为 0") 
3.2.2 直接捕获Exception

Exception:用于捕获并处理 try块中抛出的异常。你可以指定特定类型的异常来捕获,或者不指定任何类型以捕获所有异常。

代码示例:

# 将异常作为参数直接打印出来。
def func(num):
 return 1/num
def func2():
 l = [1]
 return l[1]
try:
 num = 1
 func(num)
 func2()
except Exception as e:
 print(e)
3.2.3 finally关键字

finally:无论是否发生异常,finally块中的代码都会被执行。这对于确保资源释放(如关闭文件、网络连接等)非常有用,防止资源泄露。

代码示例:

# finally的代码块无论是否有异常都会执行。
def func2():
 l = [1]
 return l[1]
try:
 func2()
except Exception as e:
 print(e)
finally:
 print("-----")
3.2.4 自定义异常

在Python中,自定义异常是面向对象编程中的一个重要特性,允许开发者根据程序的具体需求定义新的异常类型。这样做可以提高代码的清晰度和可维护性,使得错误处理更加灵活和具体。

自定义异常通常是通过创建一个新的类来实现的,这个类需要继承自Python的内置异常类Exception或者它的子类。

代码示例:

# 自定义一个基础校验异常。
class UnderAgeError(Exception):
    """当年龄小于18岁时抛出"""
    def __init__(self, age, message="年龄未满18岁"):
        self.age = age
        self.message = message
        super().__init__(f"{message}(当前年龄:{age})")
# 验证函数
def validate_age(age):
    if age < 18:
        raise UnderAgeError(age)
    return True

# 测试函数
def register_user(age):
    try:
        validate_age(age)
        print("注册成功!")
    except Exception as e:
        print(f"注册失败:{e}")

# 测试用例
if __name__ == "__main__":
    test_ages = [16, 25]

    for age in test_ages:
        try:
            print(f"\n测试年龄:{age}")
            register_user(age)
        except Exception as e:
            print(f"捕获到意外错误:{e}")

3.3 购物支付系统

结合上面的知识点,来看一个购物支付系统小程序。完整代码参考如下(注意:复制使用请保持缩进相同)。

# 一个保证健壮性的支付系统。
import datetime
import logging
import random

# 配置日志记录
logging.basicConfig(filename='transactions.log', level=logging.INFO)

# 自定义异常体系
class PaymentGatewayError(Exception):
    """支付网关异常基类"""
    def __init__(self, code, message, original=None):
        super().__init__(message)
        self.code = code
        self.timestamp = datetime.datetime.now()
        self.original = original

class InsufficientFundsError(PaymentGatewayError):
    """余额不足异常"""
    def __init__(self, balance, amount):
        message = f"余额不足 (当前余额: {balance}, 需要支付: {amount})"
        super().__init__(code=1001, message=message)

class NetworkTimeoutError(PaymentGatewayError):
    """网络超时异常"""
    def __init__(self, service_name):
        message = f"{service_name} 服务响应超时"
        super().__init__(code=2001, message=message)

# 业务逻辑类
class ECommerceSystem:
    def __init__(self, inventory=10):
        self.inventory = inventory
        self.connections = []

    def validate_order(self, order):
        """订单验证(演示多种验证异常)"""
        if not isinstance(order, dict):
            raise TypeError("订单必须是字典类型")

        required_fields = ['user_id', 'product_id', 'quantity']
        for field in required_fields:
            if field not in order:
                raise KeyError(f"缺少必要字段: {field}")

        if order['quantity'] <= 0:
            raise ValueError("购买数量必须大于0")

        assert isinstance(order['user_id'], int), "用户ID必须是整数"

    def process_payment(self, amount):
        """支付处理(演示自定义异常和异常链)"""
        try:
            # 模拟第三方支付调用
            if random.random() < 0.3:
                raise ConnectionError("支付网关连接失败")

            balance = 100  # 模拟用户余额
            if amount > balance:
                raise InsufficientFundsError(balance, amount)

            return True
        except ConnectionError as e:
            logging.error("支付网关通信失败")
            raise NetworkTimeoutError("支付网关") from e

    def handle_order(self, order):
        """订单处理主逻辑"""
        try:
            print("\n开始处理订单:", order)

            # 验证订单
            self.validate_order(order)

            # 检查库存
            if order['quantity'] > self.inventory:
                raise InventoryError(self.inventory, order['quantity'])

            # 处理支付
            amount = order['quantity'] * 100  # 模拟金额计算
            payment_result = self.process_payment(amount)

            # 扣减库存
            self.inventory -= order['quantity']

        except (TypeError, ValueError, KeyError, AssertionError) as e:
            error_msg = f"订单验证失败: {type(e).__name__} - {str(e)}"
            logging.warning(error_msg)
            raise ValidationError("订单数据不合法") from e

        except InventoryError as e:
            logging.error(str(e))
            print("库存不足,触发补货流程...")
            self.restock(e.required - e.available)
            raise

        except PaymentGatewayError as e:
            logging.error(f"支付失败 [{e.code}]: {e}")
            if isinstance(e, NetworkTimeoutError):
                print("正在重试支付...")
                return self.process_payment(amount)
            raise

        except Exception as e:
            logging.critical(f"未处理的异常: {type(e).__name__} - {str(e)}")
            raise ECommerceSystemError("系统错误") from e
        else:
            logging.info(f"订单处理成功: {order}")
            print("发送订单确认邮件...")
            return True
        finally:
            print("释放数据库连接...")
            self.connections.clear()

    def restock(self, quantity):
        """补货操作(演示finally和资源清理)"""
        try:
            print(f"正在补货 {quantity} 件...")
            if quantity <= 0:
                raise ValueError("补货数量必须为正数")
            self.inventory += quantity
        finally:
            print("补货流程结束")

# 辅助异常类
class ValidationError(Exception):
    """验证异常"""
    pass

class InventoryError(Exception):
    """库存异常"""
    def __init__(self, available, required):
        super().__init__(f"库存不足 (当前: {available}, 需要: {required})")
        self.available = available
        self.required = required

class ECommerceSystemError(Exception):
    """系统级异常"""
    pass

# --------------------------
# 测试用例
# --------------------------
if __name__ == "__main__":
    system = ECommerceSystem()

    test_orders = [
        "invalid_order",  # 类型错误
        {'user_id': "123", 'product_id': 1},  # 字段缺失
        {'user_id': 123, 'product_id': 1, 'quantity': -2},  # 数量错误
        {'user_id': 123, 'product_id': 1, 'quantity': 20},  # 库存不足
        {'user_id': 123, 'product_id': 1, 'quantity': 5},  # 正常订单
    ]

    for idx, order in enumerate(test_orders, 1):
        try:
            print(f"\n=== 处理订单 {idx} ===")
            system.handle_order(order)
        except ValidationError as e:
            print(f"订单验证失败: {e}")
        except InventoryError as e:
            print(f"库存错误: {e}")
        except PaymentGatewayError as e:
            print(f"支付失败 [{e.code}]: {e}")
        except ECommerceSystemError as e:
            print(f"系统错误: {e}")
        else:
            print("订单处理成功!")
        finally:
            print("当前库存:", system.inventory)
            print("-" * 40)

同时,可以参考上面代码进行扩展练习,例如:模拟银行卡余额不足,直接切换银行卡支付等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值