📢 大家好!今天我们来深入学习 Python 中函数的高级特性和异常处理机制。这篇文章将涵盖函数说明文档、嵌套调用、作用域、多种传参方式、匿名函数,以及异常捕获等核心知识点。
📚 目录
一、函数进阶
1.1 函数说明文档
1.2 函数的嵌套调用
1.3 变量的作用域
1.4 函数多返回值
1.5 函数多种传参方式
1.6 匿名函数(lambda)
二、异常处理
2.1 了解异常
2.2 异常的捕获方法
三、总结
一、函数进阶
1.1 函数说明文档
在 Python 中,函数说明文档(即文档字符串)就是写在函数定义内部第一行、用三个引号"""括起来的注释性文字。它的作用是向使用者清晰地说明这个函数是干什么的、怎么用。
简单理解:函数说明文档就是函数的"使用说明书"。
基础语法
def func(x, y): """ 函数说明 :param x: 形参 x 的说明 :param y: 形参 y 的说明 :return: 返回值的说明 """ return x + y
示例代码
def add(x, y): """ 两数相加 :param x: 相加的数字1 :param y: 相加的数字2 :return: 返回相加的结果 """ return x + y # 调用函数 result = add(3, 5) print(result) # 输出: 8
查看函数说明文档
在 PyCharm 等 IDE 中,编写代码时可以通过鼠标悬停查看调用函数的说明文档。
# 鼠标悬停在 add 函数上,即可看到说明文档 add(10, 20)
💡 最佳实践
使用三引号
"""编写文档字符串说明函数的功能、参数含义和返回值
遵循
param和return的规范格式IDE 会识别并显示这些文档信息
1.2 函数的嵌套调用
所谓函数嵌套调用,指的是一个函数里面又调用了另外一个函数。
python
def func_b(): print("---2---") def func_a(): print("---1---") func_b() # 在 func_a 中调用 func_b print("---3---") # 调用函数 func_a func_a()运行结果:
---1--- ---2--- ---3---
执行流程图
调用 func_a() ↓ 执行 print("---1---") ↓ 调用 func_b() ↓ 执行 print("---2---") ↓ 返回 func_a() ↓ 执行 print("---3---") ↓ 结束嵌套调用的应用场景
将复杂功能拆分成多个小函数
代码复用,避免重复编写
提高代码的可读性和可维护性
1.3 变量的作用域
变量作用域指的是变量的作用范围(变量在哪里可用,在哪里不可用)。
主要分为两类:局部变量和全局变量。
局部变量
所谓局部变量,是定义在函数体内部的变量,即只在函数体内部生效。
def test_a(): num = 100 # 局部变量 print(num) test_a() # 输出: 100 # print(num) # ❌ 报错: NameError: name 'num' is not defined
局部变量的特点:
在函数体内部临时保存数据
当函数调用完成后,局部变量被销毁
函数外部无法访问
全局变量
所谓全局变量,指的是在函数体内、外都能生效的变量。
# 定义全局变量 num = 100 def test_a(): print(num) # 访问全局变量 def test_b(): print(num) # 访问全局变量 test_a() # 输出: 100 test_b() # 输出: 100
global 关键字
如果在函数内部需要修改全局变量,需要使用global关键字声明。
python
num = 100 def test_a(): print(num) # 访问全局变量 def test_b(): # ❌ 错误写法:这会在函数内创建一个新的局部变量 # num = 200 # print(num) # 输出: 200(但全局变量没有被修改) # ✅ 正确写法:使用 global 关键字声明 global num num = 200 # 修改全局变量 print(num) test_a() # 输出: 100 test_b() # 输出: 200 print(f"全局变量 num = {num}") # 输出: 全局变量 num = 200变量作用域总结
| 变量类型 | 定义位置 | 作用范围 | 关键字 |
|---|---|---|---|
| 局部变量 | 函数内部 | 仅函数内部有效 | 无 |
| 全局变量 | 函数外部 | 整个文件有效 | global(修改时使用) |
1.4 函数多返回值
函数多返回值,顾名思义,就是一个函数在执行完毕后,可以同时返回多个结果,而不是只能返回一个。
def test_return(): return 1, 2 # 返回多个值 # 使用多个变量接收返回值 x, y = test_return() print(x) # 输出: 1 print(y) # 输出: 2
多返回值的特性
按照返回值的顺序,用对应顺序的多个变量接收
变量之间用逗号隔开
支持不同类型的数据同时返回
def get_user_info(): return "小明", 18, 175.5, True name, age, height, is_student = get_user_info() print(f"姓名: {name}, 年龄: {age}, 身高: {height}, 是否学生: {is_student}") # 输出: 姓名: 小明, 年龄: 18, 身高: 175.5, 是否学生: True多返回值的本质
实际上,Python 会将多个返回值打包成一个元组(tuple):
def test_return(): return 1, 2, 3 result = test_return() print(result) # 输出: (1, 2, 3) print(type(result)) # 输出: <class 'tuple'>
1.5 函数多种传参方式
在 Python 中,函数有多种传参方式,包括:位置参数、关键字参数、缺省参数、不定长参数。
位置参数
调用函数时根据函数定义的参数位置来传递参数。
def user_info(name, age, gender): print(f"您的名字是 {name}, 年龄是 {age}, 性别是 {gender}") # 位置传参:必须按照顺序和个数一致 user_info('TOM', 20, '男') # 正确 ✅ # user_info('TOM', 20) # ❌ 缺少参数 # user_info('TOM', 20, '男', '身高') # ❌ 参数过多关键字参数
函数调用时通过key=value形式传递参数,可以清除参数的顺序需求。
def user_info(name, age, gender): print(f"您的名字是 {name}, 年龄是 {age}, 性别是 {gender}") # 关键字传参:可以不按照顺序 user_info(name="小明", age=20, gender="男") user_info(age=20, gender="男", name="小明") # ✅ 顺序可以打乱 # 位置参数和关键字参数可以混用 # 注意:位置参数必须在关键字参数的前面! user_info("小明", age=20, gender="男") # ✅ # user_info(name="小明", 20, "男") # ❌ 位置参数在关键字参数之后缺省(默认值)参数
缺省参数也叫默认参数,用于定义函数时为参数提供默认值。
def user_info(name, age, gender='男'): print(f"您的名字是 {name}, 年龄是 {age}, 性别是 {gender}") # 不传递默认参数,使用默认值 user_info('TOM', 20) # 输出: 您的名字是 TOM, 年龄是 20, 性别是 男 # 传递默认参数,覆盖默认值 user_info('ROSE', 18, '女') # 输出: 您的名字是 ROSE, 年龄是 18, 性别是 女⚠️ 注意事项
所有位置参数必须出现在默认参数前(包括函数定义和调用)
函数调用时,如果为缺省参数传值,则修改默认参数值
如果不传递,则使用默认值
# ✅ 正确:默认参数在最后 def func(a, b, c=10): pass # ❌ 错误:默认参数不能在位置参数之前 # def func(a=10, b, c): # pass
不定长参数
位置传递*args
使用*args可以接收任意数量的位置参数,这些参数会被打包成一个元组(tuple)。
def user_info(*args): print(args) # args 是一个元组 user_info('TOM') # 输出: ('TOM',) user_info('TOM', 18) # 输出: ('TOM', 18) user_info('TOM', 18, 175) # 输出: ('TOM', 18, 175)关键字传递**kwargs
使用**kwargs可以接收任意数量的关键字参数,这些参数会被打包成一个字典(dict)。
def user_info(**kwargs): print(kwargs) # kwargs 是一个字典 user_info(name='TOM', age=18, id=110) # 输出: {'name': 'TOM', 'age': 18, 'id': 110}组合使用
def user_info(name, *args, **kwargs): print(f"姓名: {name}") print(f"其他位置参数: {args}") print(f"其他关键字参数: {kwargs}") user_info('TOM', 18, '男', height=175, weight=65) # 输出: # 姓名: TOM # 其他位置参数: (18, '男') # 其他关键字参数: {'height': 175, 'weight': 65}传参方式总结
| 方式 | 定义语法 | 调用语法 | 特点 |
|---|---|---|---|
| 位置参数 | def f(a, b) | f(1, 2) | 按顺序传递,必须一致 |
| 关键字参数 | def f(a, b) | f(a=1, b=2) | 顺序任意,清晰明确 |
| 缺省参数 | def f(a, b=10) | f(1) | 提供默认值 |
| 不定长参数 | def f(*args) | f(1, 2, 3) | 接收任意数量位置参数 |
| 关键字不定长 | def f(**kwargs) | f(a=1, b=2) | 接收任意数量关键字参数 |
1.6 匿名函数(lambda)
在 Python 中,匿名函数就是没有名字的函数,用关键字lambda来定义。因为它不需要用def给函数起名,所以也叫lambda 函数。
简单理解:匿名函数就是一行代码就能写完的"小工具函数",用完即扔,不需要给它起个正式的名字。
lambda 表达式语法
lambda 形参1, 形参2, ... : 单行表达式或函数调用
注意点:
匿名函数中不能使用 while 循环、for 循环,只能编写单行的表达式或函数调用
返回结果不需要使用
return,表达式的运行结果就是返回结果匿名函数中也可以不返回结果,例如:
lambda: print('Hello World')
基本示例
# 普通函数 def func_sum(a, b): return a + b # lambda 表达式 func = lambda a, b: a + b result = func(2, 3) print(result) # 输出: 5
lambda 的应用场景
1. 作为参数传递(配合内置函数)
# 使用 lambda 作为排序规则 students = [ {'name': '张三', 'age': 20}, {'name': '李四', 'age': 18}, {'name': '王五', 'age': 22} ] # 按年龄排序 students.sort(key=lambda x: x['age']) print(students) # 输出: [{'name': '李四', 'age': 18}, {'name': '张三', 'age': 20}, {'name': '王五', 'age': 22}]2. 配合map()函数
numbers = [1, 2, 3, 4, 5] squared = list(map(lambda x: x ** 2, numbers)) print(squared) # 输出: [1, 4, 9, 16, 25]
3. 配合filter()函数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] even_numbers = list(filter(lambda x: x % 2 == 0, numbers)) print(even_numbers) # 输出: [2, 4, 6, 8, 10]
4. 配合reduce()函数
from functools import reduce numbers = [1, 2, 3, 4, 5] product = reduce(lambda x, y: x * y, numbers) print(product) # 输出: 120
lambda 的局限性
| 特性 | lambda | def 函数 |
|---|---|---|
| 只能单行表达式 | ✅ | ❌ |
| 支持多行语句 | ❌ | ✅ |
| 支持循环 | ❌ | ✅ |
| 支持条件判断 | ✅(用三元表达式) | ✅ |
| 支持异常处理 | ❌ | ✅ |
| 有函数名 | ❌ | ✅ |
# ✅ lambda 可以做的 lambda x: x > 10 lambda x, y: x + y lambda x: x if x > 0 else -x # ❌ lambda 不能做的 # lambda x: if x > 0: return x else: return -x # 语法错误 # lambda x: for i in range(x): print(i) # 语法错误 # lambda x: try: x/0 except: pass # 语法错误
二、异常处理
2.1 了解异常
当检测到一个错误时,Python 解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的"异常",也就是我们常说的BUG。
# 这段代码会引发异常 print(1 / 0) # ZeroDivisionError: division by zero
当程序遇到 BUG 时,会有两种情况:
整个程序因一个 BUG 停止运行
对 BUG 进行提醒,整个程序继续运行
显然,我们更希望达到第二种情况——程序不会因为一个小错误而完全崩溃。这时我们就需要使用异常捕获。
2.2 异常的捕获方法
基本语法
try: # 可能发生异常的代码 print(name) # name 未定义 except Exception as e: # 发生异常时执行的代码 print(f"异常信息: {e}") print("程序继续执行...") # ✅ 这行代码会执行运行结果:
异常信息: name 'name' is not defined 程序继续执行...
捕获指定异常
try: # 可能发生异常的代码 num = int(input("请输入数字: ")) result = 100 / num except ZeroDivisionError: print("除数不能为 0") except ValueError: print("请输入有效的数字") except Exception as e: print(f"其他异常: {e}")异常 else
else表示的是没有异常时要执行的代码。
try: print("开始执行...") num = int(input("请输入数字: ")) result = 100 / num except ZeroDivisionError: print("除数不能为 0") except ValueError: print("请输入有效的数字") else: print("没有异常,真开心!") print(f"计算结果: {result}")异常的 finally
finally表示的是无论是否异常都要执行的代码,例如关闭文件。
try: f = open('test.txt', 'r') content = f.read() print(content) except Exception as e: print(f"发生异常: {e}") else: print("没有异常,读取成功") finally: print("无论是否异常,都会执行 finally") f.close() # 确保文件被关闭捕获所有异常
try: # 可能出错的代码 print(name) except Exception as e: # 捕获所有异常 print(f"程序出错了: {e}") print("但程序不会崩溃,继续执行...") print("程序结束")异常捕获的完整结构
try: # 尝试执行的代码 pass except 异常类型1: # 发生特定异常时执行 pass except 异常类型2: # 发生另一种异常时执行 pass except Exception as e: # 捕获所有其他异常 print(f"未知错误: {e}") else: # 没有异常时执行 pass finally: # 无论是否异常都会执行 pass三、总结
函数进阶要点
| 概念 | 说明 | 关键字 |
|---|---|---|
| 函数说明文档 | 函数的"使用说明书" | """docstring""" |
| 嵌套调用 | 函数内部调用其他函数 | 无 |
| 局部变量 | 函数内定义,仅函数内有效 | 无 |
| 全局变量 | 函数外定义,全局有效 | global |
| 多返回值 | 返回多个值 | return a, b, c |
| 位置参数 | 按位置传递 | 无 |
| 关键字参数 | 按名称传递 | key=value |
| 缺省参数 | 提供默认值 | def f(a, b=10) |
| 不定长参数 | 接收任意参数 | *args,**kwargs |
| 匿名函数 | 没有名字的函数 | lambda |
异常处理要点
| 关键字 | 说明 |
|---|---|
try | 尝试执行代码块 |
except | 捕获并处理异常 |
else | 无异常时执行 |
finally | 无论是否异常都执行 |
raise | 主动抛出异常 |
💡 最佳实践
异常具体化:尽量捕获具体的异常类型,而不是直接使用
Exception及时释放资源:在
finally中释放文件、数据库连接等资源不要忽略异常:捕获异常后应记录日志或做适当处理
lambda 保持简单:复杂的逻辑用普通函数,简单的用 lambda
合理使用默认参数:可以减少调用时的参数传递
📝最后提醒:函数进阶和异常处理是 Python 编程中非常重要的内容,掌握好这些知识,你就能写出更加健壮、优雅的代码。多敲代码、多实践,自然就能熟练运用!
如果觉得有帮助,欢迎点赞、收藏、评论!😊