欢迎回来!在前面的章节中,我们已经掌握了函数的基本用法、各种数据容器和字符串操作。今天,我们将学习函数的进阶特性,让我们的代码更加灵活和强大!
想象一下这些场景:
- 需要对不同类型的数据使用相同的处理流程
- 函数需要返回多个相关的结果
- 需要一个简单的临时函数,不想费心命名
这些都需要用到我们今天要学的知识!
1. 函数作为参数传递:让函数更灵活
为什么需要函数作为参数?
有时我们希望同一个函数框架能处理不同的逻辑,就像模板一样:
# 问题:我们有两个相似的函数
def process_numbers_v1(numbers):
"""处理数字:计算平方和"""
result = 0
for num in numbers:
result += num * num
return result
def process_numbers_v2(numbers):
"""处理数字:计算立方和"""
result = 0
for num in numbers:
result += num * num * num
return result
# 缺点:大量重复代码!如果要计算四次方和,还要再写一个...
解决方案:把处理逻辑作为参数传递
# 定义一个通用的处理函数
def process_numbers(numbers, operation):
"""
通用数字处理函数
参数:
numbers -- 数字列表
operation -- 处理函数,接受一个数字返回处理结果
"""
result = 0
for num in numbers:
result += operation(num) # 使用传入的函数处理每个数字
return result
# 定义具体的处理函数
def square(x):
"""计算平方"""
return x * x
def cube(x):
"""计算立方"""
return x * x * x
def double(x):
"""计算两倍"""
return x * 2
# 使用通用函数处理不同的需求
numbers = [1, 2, 3, 4, 5]
print("平方和:", process_numbers(numbers, square)) # 55
print("立方和:", process_numbers(numbers, cube)) # 225
print("两倍和:", process_numbers(numbers, double)) # 30
更实际的例子:数据过滤
def filter_students(students, criteria_func):
"""
过滤学生
参数:
students -- 学生列表
criteria_func -- 过滤条件函数,返回True表示保留
"""
filtered = []
for student in students:
if criteria_func(student): # 使用传入的函数判断
filtered.append(student)
return filtered
# 学生数据
students = [
{"name": "小明", "age": 16, "score": 85},
{"name": "小红", "age": 17, "score": 92},
{"name": "小刚", "age": 16, "score": 78},
{"name": "小李", "age": 18, "score": 90},
{"name": "小芳", "age": 17, "score": 88}
]
# 定义不同的过滤条件
def is_high_score(student):
"""成绩大于等于90"""
return student["score"] >= 90
def is_young(student):
"""年龄小于18"""
return student["age"] < 18
def is_excellent(student):
"""成绩大于85且年龄小于18"""
return student["score"] > 85 and student["age"] < 18
# 使用不同的过滤条件
print("高分学生(≥90):")
for student in filter_students(students, is_high_score):
print(f"- {student['name']}: {student['score']}分")
print("\n年轻学生(<18岁):")
for student in filter_students(students, is_young):
print(f"- {student['name']}: {student['age']}岁")
print("\n优秀学生(成绩>85且年龄<18):")
for student in filter_students(students, is_excellent):
print(f"- {student['name']}: {student['age']}岁, {student['score']}分")
二、函数返回多个值:元组的妙用
基本用法:用元组返回多个值
# 函数定义:返回多个值
def get_student_info(student_id):
"""根据学号获取学生信息"""
# 模拟数据库查询
database = {
"2023001": ("小明", 16, "高一", 85),
"2023002": ("小红", 17, "高二", 92),
"2023003": ("小刚", 16, "高一", 78)
}
if student_id in database:
return database[student_id] # 返回元组
else:
return None
# 调用函数接收多个返回值
info = get_student_info("2023001")
if info:
name, age, grade, score = info # 元组解包
print(f"姓名: {name}")
print(f"年龄: {age}")
print(f"年级: {grade}")
print(f"成绩: {score}")
# 或者直接解包接收
name, age, grade, score = get_student_info("2023002")
print(f"\n{name}的信息: {age}岁, {grade}, {score}分")
更实用的例子:计算统计信息
def analyze_scores(scores):
"""
分析成绩数据
返回:
(最高分, 最低分, 平均分, 及格人数)
"""
if not scores: # 如果列表为空
return 0, 0, 0, 0
max_score = max(scores)
min_score = min(scores)
average = sum(scores) / len(scores)
# 统计及格人数(≥60)
pass_count = 0
for score in scores:
if score >= 60:
pass_count += 1
return max_score, min_score, average, pass_count
# 测试数据
test_scores = [85, 92, 78, 45, 90, 88, 95, 60, 72, 58]
# 接收多个返回值
highest, lowest, avg, pass_num = analyze_scores(test_scores)
print("成绩分析结果:")
print(f"最高分: {highest}")
print(f"最低分: {lowest}")
print(f"平均分: {avg:.1f}")
print(f"及格人数: {pass_num}/{len(test_scores)}")
# 也可以只接收部分返回值
_, lowest_score, _, _ = analyze_scores(test_scores) # 只关心最低分
print(f"\n只获取最低分: {lowest_score}")
返回字典:更清晰的多个值
def get_student_details(student_id):
"""获取学生详细信息(返回字典)"""
database = {
"2023001": {
"name": "小明",
"age": 16,
"grade": "高一",
"scores": {"语文": 85, "数学": 92, "英语": 88},
"hobbies": ["篮球", "音乐"]
},
"2023002": {
"name": "小红",
"age": 17,
"grade": "高二",
"scores": {"语文": 90, "数学": 85, "英语": 92},
"hobbies": ["阅读", "绘画"]
}
}
return database.get(student_id, {})
# 使用
details = get_student_details("2023001")
if details:
print(f"学生: {details['name']}")
print(f"年龄: {details['age']}")
print(f"爱好: {', '.join(details['hobbies'])}")
# 计算平均分
scores = list(details["scores"].values())
average = sum(scores) / len(scores)
print(f"平均分: {average:.1f}")
结合应用:计算器和多个结果
def calculate_rectangle(length, width):
"""计算矩形的各种属性"""
area = length * width
perimeter = 2 * (length + width)
diagonal = (length ** 2 + width ** 2) ** 0.5 # 对角线
# 返回多个值
return {
"长": length,
"宽": width,
"面积": area,
"周长": perimeter,
"对角线": diagonal
}
# 使用
results = calculate_rectangle(10, 5)
print("矩形计算结果:")
for key, value in results.items():
if key in ["长", "宽"]:
print(f"{key}: {value}")
else:
print(f"{key}: {value:.2f}")
# 还可以这样使用
def compare_rectangles(rect1_length, rect1_width, rect2_length, rect2_width):
"""比较两个矩形"""
rect1 = calculate_rectangle(rect1_length, rect1_width)
rect2 = calculate_rectangle(rect2_length, rect2_width)
return rect1, rect2 # 返回两个字典
# 比较两个矩形
rect_a, rect_b = compare_rectangles(10, 5, 8, 6)
print(f"\n矩形A面积: {rect_a['面积']}")
print(f"矩形B面积: {rect_b['面积']}")
if rect_a['面积'] > rect_b['面积']:
print("矩形A更大")
else:
print("矩形B更大")
三、lambda表达式:匿名函数的魔法
什么是lambda表达式?
lambda表达式用于创建简单的匿名函数(没有名字的函数)。
# 传统函数定义
def square(x):
return x * x
# lambda表达式
square_lambda = lambda x: x * x
# 两种方式效果相同
print(square(5)) # 25
print(square_lambda(5)) # 25
lambda的基本语法
# 语法:lambda 参数: 表达式
# 示例:
add = lambda a, b: a + b
is_even = lambda x: x % 2 == 0
get_first = lambda s: s[0]
print(add(10, 20)) # 30
print(is_even(7)) # False
print(get_first("Hello")) # H
lambda的典型应用场景
场景1:作为函数参数(最常用!)
# 配合 sorted() 使用
students = [
{"name": "小明", "score": 85, "age": 16},
{"name": "小红", "score": 92, "age": 17},
{"name": "小刚", "score": 78, "age": 16}
]
# 按成绩排序
sorted_by_score = sorted(students, key=lambda s: s["score"])
print("按成绩排序:")
for s in sorted_by_score:
print(f"- {s['name']}: {s['score']}分")
# 按年龄排序
sorted_by_age = sorted(students, key=lambda s: s["age"])
print("\n按年龄排序:")
for s in sorted_by_age:
print(f"- {s['name']}: {s['age']}岁")
# 按成绩降序排序
sorted_by_score_desc = sorted(students, key=lambda s: s["score"], reverse=True)
print("\n按成绩降序排序:")
for s in sorted_by_score_desc:
print(f"- {s['name']}: {s['score']}分")
场景2:配合 map()、filter()、reduce() 使用
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 1. map():对每个元素应用函数
squares = list(map(lambda x: x * x, numbers))
print("平方数:", squares)
# 2. filter():过滤元素
evens = list(filter(lambda x: x % 2 == 0, numbers))
print("偶数:", evens)
# 3. 复杂一点的过滤
scores = [85, 92, 78, 45, 90, 88, 95, 60, 72, 58]
good_scores = list(filter(lambda x: 80 <= x <= 90, scores))
print("良好分数(80-90):", good_scores)
场景3:简单的条件判断
# 传统写法
def get_grade(score):
if score >= 90:
return "优秀"
elif score >= 80:
return "良好"
elif score >= 60:
return "及格"
else:
return "不及格"
# lambda写法(虽然不太适合复杂逻辑,但可以这样写)
get_grade_lambda = lambda score: (
"优秀" if score >= 90 else
"良好" if score >= 80 else
"及格" if score >= 60 else
"不及格"
)
# 测试
scores = [95, 85, 72, 55]
for score in scores:
grade1 = get_grade(score)
grade2 = get_grade_lambda(score)
print(f"{score}分: {grade1} (函数) / {grade2} (lambda)")
lambda的注意事项
# 1. lambda只能包含一个表达式,不能包含语句
# valid_lambda = lambda x: x * x # 正确
# invalid_lambda = lambda x: print(x) # 正确(print()返回None)
# invalid_lambda2 = lambda x: for i in range(x): print(i) # 错误!不能有for循环
# 2. lambda可以有多个参数
add_three = lambda a, b, c: a + b + c
print(f"三个数相加: {add_three(1, 2, 3)}") # 6
# 3. lambda可以没有参数
get_pi = lambda: 3.14159
print(f"圆周率: {get_pi()}") # 3.14159
# 4. lambda的嵌套使用(不推荐,可读性差)
complex_lambda = lambda x: (lambda y: x + y)
result = complex_lambda(10)(20)
print(f"嵌套lambda结果: {result}") # 30
# 5. 正确使用lambda:保持简单
# 好的用法:简单的转换或判断
# 不好的用法:复杂的逻辑(应该用普通函数)
四、综合实战:学生成绩分析系统
def process_student_data(students, filter_func=None, sort_func=None, process_func=None):
"""
处理学生数据的通用函数
参数:
students -- 学生列表
filter_func -- 过滤函数
sort_func -- 排序函数
process_func -- 处理函数
返回:
处理后的学生列表
"""
result = students.copy()
# 1. 过滤
if filter_func:
result = [s for s in result if filter_func(s)]
# 2. 排序
if sort_func:
result.sort(key=sort_func)
# 3. 处理
if process_func:
result = [process_func(s) for s in result]
return result
def display_students(students, title=""):
"""显示学生信息"""
if title:
print(f"\n{title}")
print("=" * 40)
if not students:
print("没有学生数据")
return
for i, student in enumerate(students, 1):
if isinstance(student, dict):
print(f"{i}. {student['name']} - {student['age']}岁 - {student['score']}分")
else:
print(f"{i}. {student}")
def main():
"""主程序"""
# 学生数据
students = [
{"name": "小明", "age": 16, "score": 85, "grade": "高一"},
{"name": "小红", "age": 17, "score": 92, "grade": "高二"},
{"name": "小刚", "age": 16, "score": 78, "grade": "高一"},
{"name": "小李", "age": 18, "score": 90, "grade": "高三"},
{"name": "小芳", "age": 17, "score": 88, "grade": "高二"},
{"name": "小强", "age": 16, "score": 95, "grade": "高一"},
{"name": "小丽", "age": 18, "score": 82, "grade": "高三"}
]
print("原始学生数据:")
display_students(students)
# 场景1:找出高一的学生并按成绩排序
print("\n" + "="*50)
print("场景1:高一学生按成绩排序")
high1_students = process_student_data(
students,
filter_func=lambda s: s["grade"] == "高一", # 过滤高一学生
sort_func=lambda s: s["score"], # 按成绩排序
process_func=lambda s: f"{s['name']} ({s['score']}分)" # 格式化输出
)
display_students(high1_students, "高一学生(按成绩升序)")
# 场景2:找出成绩优秀(≥90)的学生按年龄排序
print("\n" + "="*50)
print("场景2:优秀学生按年龄排序")
excellent_students = process_student_data(
students,
filter_func=lambda s: s["score"] >= 90,
sort_func=lambda s: s["age"],
process_func=lambda s: {
"姓名": s["name"],
"年龄": s["age"],
"成绩": s["score"],
"年级": s["grade"]
}
)
display_students(excellent_students, "优秀学生(≥90分,按年龄排序)")
# 场景3:给所有学生加分并找出新分数≥90的学生
print("\n" + "="*50)
print("场景3:加分后的优秀学生")
def add_bonus(student):
"""加分函数"""
new_student = student.copy()
bonus = 5 if student["age"] < 18 else 3 # 年龄小的多加
new_student["score"] += bonus
new_student["bonus"] = bonus
return new_student
after_bonus = process_student_data(
students,
process_func=add_bonus,
filter_func=lambda s: s["score"] >= 90 # 过滤加分后≥90的学生
)
print("加分后≥90分的学生:")
for student in after_bonus:
print(f"- {student['name']}: 原{student['score']-student['bonus']}分 + {student['bonus']}分 = {student['score']}分")
# 场景4:统计函数返回多个值
print("\n" + "="*50)
print("场景4:年级统计")
def analyze_by_grade(all_students):
"""按年级统计"""
grade_stats = {}
for student in all_students:
grade = student["grade"]
if grade not in grade_stats:
grade_stats[grade] = {
"count": 0,
"total_score": 0,
"students": []
}
grade_stats[grade]["count"] += 1
grade_stats[grade]["total_score"] += student["score"]
grade_stats[grade]["students"].append(student["name"])
# 计算平均分
for grade, stats in grade_stats.items():
stats["average"] = stats["total_score"] / stats["count"]
return grade_stats
stats = analyze_by_grade(students)
print("各年级统计:")
for grade, data in stats.items():
print(f"{grade}: {data['count']}人,平均分: {data['average']:.1f}")
print(f" 学生: {', '.join(data['students'])}")
if __name__ == "__main__":
main()
总结一下
今天,我们学习了函数的三个进阶特性:
1. 函数作为参数传递
- 作用:让函数更加灵活通用
- 应用场景:回调函数、模板模式、策略模式
- 典型应用:
sorted(key=...)、map()、filter()
2. 函数返回多个值
- 实质:返回元组(自动打包和解包)
- 优点:让函数接口更清晰,减少函数数量
- 应用场景:计算多个相关结果、获取复杂数据
3. lambda表达式(匿名函数)
- 特点:简洁、匿名、一次性使用
- 语法:
lambda 参数: 表达式 - 适用场景:简单的转换、过滤、排序规则
- 注意:保持简单,复杂逻辑用普通函数
核心概念对比:
|
特性 |
作用 |
示例 |
|
函数作为参数 |
使函数更灵活 |
|
|
多返回值 |
返回相关数据组 |
|
|
lambda表达式 |
创建简单匿名函数 |
|
学习成果:
学完本章,你现在能够:
- ✅ 编写接收函数作为参数的通用函数
- ✅ 让函数返回多个相关值
- ✅ 使用元组解包接收多个返回值
- ✅ 创建和使用lambda表达式
- ✅ 合理选择普通函数或lambda表达式
- ✅ 组合使用这些特性构建灵活的程序
下一步预告
今天我们已经掌握了函数的进阶用法,让代码更加灵活和强大。但在实际开发中,我们还需要处理各种异常情况,比如:
- 用户输入了错误的格式
- 文件不存在无法读取
- 网络连接突然中断
- 除数为零的数学错误
下一讲,我们将学习 《异常处理:让程序更健壮》,学习如何使用 try-except 来优雅地处理错误,让你的程序更加稳定和可靠!
动手任务
- 任务一:通用计算器
创建一个通用计算函数,可以接受不同的运算函数:
-
- 实现加、减、乘、除运算函数
- 创建一个通用计算函数,接受两个数字和一个运算函数
- 使用lambda表达式创建平方、立方运算
- 任务二:数据分析工具
创建一个学生成绩分析工具:
-
- 函数返回最高分、最低分、平均分、及格率
- 使用lambda表达式过滤不同分数段的学生
- 函数作为参数实现不同的分析策略
- 任务三:排序策略
实现一个通用的排序函数:
-
- 可以接受不同的排序规则函数
- 使用lambda表达式定义不同的排序规则
- 返回排序后的列表和排序统计信息
记住:掌握函数进阶特性是成为Python高手的关键一步!这些技能能让你的代码更加优雅、灵活和强大! 🚀

被折叠的 条评论
为什么被折叠?



