当前位置: 首页 > news >正文

Phthon3 学习记录-0611

异常处理

try         尝试执行代码块

except 捕获异常

finally  无论是否发生异常都会执行的代码块

raise    抛出异常

以下是一个综合展示 try、except、finally 和 raise 关键字用法的 Python 示例:

try:num1 = int(input("请输入第一个数字: "))num2 = int(input("请输入第二个数字: "))if num2 == 0:# raise 抛出异常,如果除数为0raise ZeroDivisionError("除数不能为零")result = num1 / num2print(f"结果是: {result}")
except ValueError:# 捕获输入非数字引发的 ValueError 异常print("输入的不是有效的数字")
except ZeroDivisionError as e:# 捕获除零异常print(f"捕获到异常: {e}")
finally:# 无论是否发生异常,都会执行这里的代码print("这是 finally 块,总会执行")

代码解释

  1. try 块
    • 尝试执行 try 块内的代码,这里尝试获取用户输入并将其转换为整数,然后进行除法运算。如果在这个过程中发生异常,程序会跳转到相应的 except 块。
  2. raise 语句
    • 在 try 块中,如果 num2 为零,通过 raise ZeroDivisionError("除数不能为零") 手动抛出一个 ZeroDivisionError 异常,并附带自定义的错误信息。
  3. except 块
    • except ValueError: 捕获用户输入非数字时引发的 ValueError 异常,并打印错误提示。
    • except ZeroDivisionError as e: 捕获 ZeroDivisionError 异常,并将异常对象赋值给 e,然后打印异常信息。
  4. finally 块
    • 无论 try 块中是否发生异常,finally 块中的代码都会执行。这里打印一条信息表明 finally 块的执行。

exceptraise 的核心区别

1. 角色定位
  • except:异常处理的接收端
    类似“消防员”,当程序运行中意外着火(发生异常)时,负责灭火(处理异常)。

    try:print(10 / 0)  # 引发异常的火源
    except ZeroDivisionError:print("错误:除数不能为零")  # 灭火动作
    
  • raise:异常生成的触发端
    类似“火警按钮”,主动触发异常事件。

    def check_age(age):if age < 0:raise ValueError("年龄不能为负数")  # 主动拉响警报
    
2. 执行阶段
关键字作用阶段执行条件
except异常发生后(被动响应)try块出现匹配的异常时
raise异常生成前(主动触发)满足特定条件时手动触发
3. 典型应用场景
  • except 的用途

    • 防止程序崩溃
    • 记录错误日志
    • 提供友好错误提示
    try:file = open("data.txt")
    except FileNotFoundError:print("文件未找到,已创建新文件")file = open("data.txt", "w")
    
  • raise 的用途

    • 参数合法性校验
    • 业务流程阻断
    • 自定义异常类型传递
    class InsufficientFundsError(Exception):passdef withdraw(balance, amount):if amount > balance:raise InsufficientFundsError("余额不足")return balance - amount
    
4. 协同工作示例
def calculate_bmi(weight, height):if height <= 0:raise ValueError("身高必须大于零")  # 主动抛出异常return weight / (height ** 2)try:print(calculate_bmi(70, 0))  # 触发异常
except ValueError as e:print(f"输入错误: {e}")        # 捕获并处理异常
finally:print("计算流程结束")          # 最终清理

5. 关键差异总结表
特征exceptraise
执行方向异常传播的终点异常传播的起点
代码位置必须跟在try块后可出现在任何代码位置
主动性被动响应已发生的异常主动创建新的异常
多级处理可捕获上级未处理的异常抛出的异常可被上层except捕获
6. 进阶理解
  • 异常传播链
    raise 抛出的异常会沿着调用栈向上传递,直到被某个except捕获或导致程序崩溃:

    def layer1():raise TypeError("类型错误")def layer2():try:layer1()except ValueError:print("不会捕获到这里的异常")try:layer2()
    except TypeError:print("捕获到传播上来的异常")  # 最终在此处被捕获
    
  • 异常上下文保留
    使用 raise from 保留原始异常信息:

    try:10 / 0
    except ZeroDivisionError as original_error:raise ValueError("计算失败") from original_error
    

掌握这两个关键字的区别,能帮助开发者更好地构建健壮的异常处理体系:通过raise精确控制错误触发点,通过except实现分层次的错误处理策略。

作用域

global关键字: 在函数内部,如果想要修改全局变量,就需要使用global关键字声明该变量。

示例代码如下

message = '初始全局消息'def change_global():global messagemessage = '修改后的全局消息'print('函数内部:', message)change_global()
print('函数外部:', message)
  • 代码解释
    • 首先定义了一个全局变量message,初始值为'初始全局消息'
    • change_global函数中,使用global message声明要修改的message是全局变量。然后对message进行赋值操作,修改了全局变量的值。
    • 函数内部打印修改后的message值,函数外部再次打印message值,此时可以看到全局变量的值已经被修改
  1. nonlocal关键字
    • 当在嵌套函数中,内部函数想要修改外部(非全局)函数的局部变量时,需要使用nonlocal关键字。
    • 示例代码如下:
def outer():num = 10def inner():nonlocal numnum = 20print('内部函数中修改后的值:', num)inner()print('外部函数中修改后的值:', num)outer()
  • 代码解释
    • outer函数中定义了局部变量num,初始值为10
    • 在内部函数inner中,使用nonlocal num声明要修改的num是外部函数outer的局部变量,而不是在inner函数中创建一个新的局部变量。然后对num进行赋值操作,修改了外部函数outernum的值。
    • 内部函数打印修改后的num值,外部函数也打印修改后的num值,表明num的值在外部函数中也被成功修改。如果不使用nonlocal关键字,在inner函数中对num赋值将会创建一个新的局部变量,而不会影响外部函数的num变量。

异步编程

  1. async关键字
    • async关键字用于定义一个异步函数。异步函数返回一个coroutine对象,该对象在适当的时候可以被await或传递给事件循环来执行。
    • 示例代码:
import asyncioasync def async_function():print('开始异步函数')await asyncio.sleep(2)print('异步函数结束')async def main():print('开始主函数')await async_function()print('主函数结束')if __name__ == '__main__':asyncio.run(main())
  • 代码解释
    • async def async_function():定义了一个异步函数async_function。在这个函数内部,首先打印'开始异步函数',然后使用await asyncio.sleep(2)暂停函数执行 2 秒,模拟一个异步操作(这里是等待 2 秒),最后打印'异步函数结束'
    • async def main():定义了另一个异步函数main。在main函数中,首先打印'开始主函数',然后使用await调用async_function,等待async_function执行完毕,最后打印'主函数结束'
    • asyncio.run(main())运行main函数,asyncio.run是 Python 3.7+ 用于运行异步函数的入口点,它会创建一个新的事件循环,并在事件循环中运行传入的协程,直到协程完成。
  1. await关键字
    • await只能在async定义的异步函数内部使用。它用于暂停当前异步函数的执行,直到被等待的coroutine(通常是一个异步操作)完成,并返回其结果。
    • 继续上面的例子,await asyncio.sleep(2)await async_function()都是await的使用场景。
    • 例如,假设我们有一个模拟异步获取数据的函数:
import asyncioasync def fetch_data():await asyncio.sleep(1)return '数据已获取'async def process_data():print('开始处理数据')result = await fetch_data()print(f'处理的数据: {result}')if __name__ == '__main__':asyncio.run(process_data())
  • 代码解释
    • async def fetch_data():定义了一个异步函数fetch_data,它使用await asyncio.sleep(1)模拟异步获取数据的延迟,1 秒后返回'数据已获取'
    • async def process_data():定义了另一个异步函数process_data。在这个函数中,首先打印'开始处理数据',然后使用await等待fetch_data函数执行完毕,并将返回的结果赋值给result,最后打印处理的数据。
    • asyncio.run(process_data())运行process_data函数,开始整个异步操作流程。

if __name__ == '__main__':

基础概念:
if __name__ == '__main__': 这行代码的作用是判断当前脚本是否是直接运行的。当 Python 脚本直接运行时,__name__ 变量会被设置为 '__main__'。如果该脚本是被其他脚本作为模块导入的,__name__ 会被设置为模块的名字。

让我们通过两个不同的使用方式来进一步理解 if __name__ == '__main__':

直接运行脚本

创建一个名为 example.py 的文件,内容如下:

def add_numbers(a, b):return a + bif __name__ == '__main__':result = add_numbers(3, 5)print(f"两数之和为: {result}")

作为模块导入

现在,假设我们有另一个文件 main_program.py,它导入 example.py

import example# 这里不会执行 example.py 中 if __name__ == '__main__': 块内的代码
# 因为此时 example 模块中的 __name__ 是 'example',而不是 '__main__'result_from_import = example.add_numbers(2, 4)
print(f"从导入模块得到的两数之和为: {result_from_import}")

在 main_program.py 中,我们导入了 example 模块,并调用了 add_numbers 函数。但 example.py 中 if __name__ == '__main__': 块内的代码并没有执行,因为当 example.py 作为模块被导入时,它的 __name__ 是模块名 'example',而不是 '__main__'

这种机制非常有用,它允许你在同一个 Python 文件中编写可复用的函数或类,同时也可以包含仅在该文件作为主程序运行时执行的测试代码或特定逻辑。这样,当其他开发者将你的代码作为模块导入到他们的项目中时,不会意外执行这些测试或特定逻辑。

if __name__ == '__main__': 是 Python 中一种固定且常用的语法结构 。它基于 Python 对模块和脚本执行的机制设计。

在 Python 中,每个模块都有一个内置变量 __name__ 。当一个 Python 文件作为脚本直接运行时,Python 解释器会将该文件的 __name__ 设置为 '__main__' 。当该文件作为模块被其他文件导入时,__name__ 则被设置为模块的名称(通常就是文件名去掉 .py 后缀)。

这种固定语法的作用主要有两点:

  1. 测试代码隔离:在开发模块时,可以在模块内编写一些测试该模块功能的代码,并放在 if __name__ == '__main__': 块中。这样当模块被导入到其他项目中时,测试代码不会被执行,而在单独运行模块文件时,测试代码会被执行,方便模块功能的调试和验证。例如:
def multiply(a, b):return a * bif __name__ == '__main__':result = multiply(3, 4)print(f"测试乘法结果: {result}")
  1. 程序入口标识:对于可执行的 Python 脚本(如命令行工具等),if __name__ == '__main__': 块可以作为程序的入口点。在这个块中可以处理命令行参数、初始化环境等操作。例如:
  2. import sysdef main():if len(sys.argv)!= 3:print("用法: python script.py <数字1> <数字2>")returnnum1 = int(sys.argv[1])num2 = int(sys.argv[2])result = num1 + num2print(f"两数之和: {result}")if __name__ == '__main__':main()

    在这个例子中,if __name__ == '__main__': 块调用 main 函数,该函数负责处理命令行参数并执行主要的程序逻辑。

  3. 列表(List)
    • 列表是一种有序的可变数据类型,可以包含不同类型的元素。
    • 示例代码:
# 创建列表
my_list = [1, 'apple', 3.14, True]# 访问列表元素
print(my_list[0])  # 输出: 1# 修改列表元素
my_list[1] = 'banana'
print(my_list)  # 输出: [1, 'banana', 3.14, True]# 添加元素到列表末尾
my_list.append('cherry')
print(my_list)  # 输出: [1, 'banana', 3.14, True, 'cherry']# 插入元素到指定位置
my_list.insert(2, 'grape')
print(my_list)  # 输出: [1, 'banana', 'grape', 3.14, True, 'cherry']# 删除元素
my_list.remove('banana')
print(my_list)  # 输出: [1, 'grape', 3.14, True, 'cherry']# 获取列表长度
print(len(my_list))  # 输出: 5
  • 代码解释
    • 首先创建了一个包含整数、字符串、浮点数和布尔值的列表 my_list
    • 通过索引访问列表元素,索引从 0 开始。
    • 可以直接通过索引修改列表元素的值。
    • 使用 append 方法在列表末尾添加元素,insert 方法在指定位置插入元素。
    • remove 方法用于删除指定元素。
    • len 函数用于获取列表的长度。

http://www.xdnf.cn/news/985159.html

相关文章:

  • Windows 删除文件出现错误代码0x80070570:文件或目录损坏且无法读取
  • 第五章网络管理
  • vibe coding 2025工具全景图
  • 构建高效开发节奏:我的IDEA休息提醒插件实践
  • fastadmin自动保存格式datetime
  • JavaEE-SpringBoot
  • 基于SpringBoot实现的课程答疑系统设计与实现【源码+文档】
  • 【MySQL数据库 | 第四篇】 数据类型+DDL表操作1
  • 从零开始了解数据采集技术篇(2)——如何提高数据采集的精度与速度
  • ALIGN_COMMA_ENABLE参数
  • 贪心选择 (Greedy Choice)
  • 大语言模型智能体开发的技术框架与应用前景
  • 日期的数据格式转换
  • 红队手法:从web漏洞到ssh横向移动 实战方案
  • vue3笔记(1)自用
  • 选择、填空、判断
  • 深入理解Python协程:async def、async for、await、yield详解
  • 学习日记-day27-6.11
  • Debian/Ubuntu systemd coredump调试程序Crash
  • 光纤传感预警工业罐体爆炸风险
  • 6.11打卡
  • PyTorch:让你的深度学习从「纸上谈兵」到「真枪实战」的魔法棒!
  • 直接使用阿里云OSS的地址,报跨域访问的问题怎么解决
  • 七牛云图片上传 前后端全过程
  • 统一事件源
  • [特殊字符] Altair:用Python说话,让数据自己讲故事!!!
  • postman调用接口报错401, Unauthorized, Invalid Token. null解决办法
  • Python自动化测试数据驱动解决数据错误
  • 多项目资源如何高效配置与再分配?
  • C++算法动态规划4