【Python学习实录 #014】:函数进阶——函数作为参数、多返回值与lambda表达式

欢迎回来!在前面的章节中,我们已经掌握了函数的基本用法、各种数据容器和字符串操作。今天,我们将学习函数的进阶特性,让我们的代码更加灵活和强大!

想象一下这些场景:

  • 需要对不同类型的数据使用相同的处理流程
  • 函数需要返回多个相关的结果
  • 需要一个简单的临时函数,不想费心命名

这些都需要用到我们今天要学的知识!

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 参数: 表达式
  • 适用场景:简单的转换、过滤、排序规则
  • 注意:保持简单,复杂逻辑用普通函数

核心概念对比:

特性

作用

示例

函数作为参数

使函数更灵活

sorted(list, key=func)

多返回值

返回相关数据组

return a, b, c

lambda表达式

创建简单匿名函数

lambda x: x*2

学习成果:

学完本章,你现在能够:

  • ✅ 编写接收函数作为参数的通用函数
  • ✅ 让函数返回多个相关值
  • ✅ 使用元组解包接收多个返回值
  • ✅ 创建和使用lambda表达式
  • ✅ 合理选择普通函数或lambda表达式
  • ✅ 组合使用这些特性构建灵活的程序

下一步预告

今天我们已经掌握了函数的进阶用法,让代码更加灵活和强大。但在实际开发中,我们还需要处理各种异常情况,比如:

  • 用户输入了错误的格式
  • 文件不存在无法读取
  • 网络连接突然中断
  • 除数为零的数学错误

下一讲,我们将学习 《异常处理:让程序更健壮》,学习如何使用 try-except 来优雅地处理错误,让你的程序更加稳定和可靠!

动手任务

  1. 任务一:通用计算器
    创建一个通用计算函数,可以接受不同的运算函数:
    • 实现加、减、乘、除运算函数
    • 创建一个通用计算函数,接受两个数字和一个运算函数
    • 使用lambda表达式创建平方、立方运算
  1. 任务二:数据分析工具
    创建一个学生成绩分析工具:
    • 函数返回最高分、最低分、平均分、及格率
    • 使用lambda表达式过滤不同分数段的学生
    • 函数作为参数实现不同的分析策略
  1. 任务三:排序策略
    实现一个通用的排序函数:
    • 可以接受不同的排序规则函数
    • 使用lambda表达式定义不同的排序规则
    • 返回排序后的列表和排序统计信息

记住:掌握函数进阶特性是成为Python高手的关键一步!这些技能能让你的代码更加优雅、灵活和强大! 🚀


 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值