Python函数高级指南:返回值、多值返回、偏函数与递归_递归

Python return函数返回值

Python中的函数通过return语句返回值给调用者。理解return的工作原理对于编写高效的Python代码至关重要。

基本用法

return语句的基本语法非常简单:

def 函数名(参数列表):
    # 函数体
    return 返回值
  • 1.
  • 2.
  • 3.

当Python执行到return语句时,函数会立即终止执行并将指定的值返回给调用者。

示例1:返回单个值
def 计算平方(数字):
    结果 = 数字 * 数字
    return 结果

# 调用函数并接收返回值
平方结果 = 计算平方(5)
print(平方结果)  # 输出: 25
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
示例2:提前返回

return语句可以用于在满足特定条件时提前结束函数执行:

def 检查年龄(年龄):
    if 年龄 < 0:
        return "年龄不能为负数"
    if 年龄 < 18:
        return "未成年"
    return "成年人"

print(检查年龄(-5))  # 输出: 年龄不能为负数
print(检查年龄(16))  # 输出: 未成年
print(检查年龄(20))  # 输出: 成年人
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
示例3:不带值的return

如果return语句不带任何值,或者函数没有return语句,函数将返回None

def 无返回值函数():
    print("这个函数没有返回值")
    return

结果 = 无返回值函数()
print(结果)  # 输出: None
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

注意事项

  1. return语句后的代码不会执行
  2. 一个函数可以有多个return语句,但只有一个会被执行
  3. 可以返回任何类型的数据,包括列表、字典、对象等

Python函数怎样返回多个值?

Python函数可以轻松地返回多个值,这是许多其他编程语言所不具备的特性。

使用元组返回多个值

最常见的方法是通过元组返回多个值:

def 获取个人信息():
    姓名 = "张三"
    年龄 = 30
    职业 = "程序员"
    return 姓名, 年龄, 职业  # 自动打包为元组

# 调用函数并解包返回值
姓名, 年龄, 职业 = 获取个人信息()
print(f"姓名: {姓名}, 年龄: {年龄}, 职业: {职业}")

# 也可以接收为单个元组
个人信息 = 获取个人信息()
print(个人信息)  # 输出: ('张三', 30, '程序员')
print(个人信息[0])  # 访问第一个值: 张三
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

使用列表返回多个值

当返回的值数量可能变化时,列表是一个好选择:

def 获取成绩单(包含不及格=False):
    所有成绩 = [85, 92, 78, 55, 60, 45, 98]
    if not 包含不及格:
        return [分数 for 分数 in 所有成绩 if 分数 >= 60]
    return 所有成绩

及格成绩 = 获取成绩单()
print(及格成绩)  # 输出: [85, 92, 78, 60, 98]

所有成绩 = 获取成绩单(True)
print(所有成绩)  # 输出: [85, 92, 78, 55, 60, 45, 98]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

使用字典返回多个值

当需要为返回的值提供标签时,字典是最佳选择:

def 计算统计数据(数字列表):
    return {
        "总和": sum(数字列表),
        "平均值": sum(数字列表) / len(数字列表),
        "最大值": max(数字列表),
        "最小值": min(数字列表),
        "数量": len(数字列表)
    }

统计结果 = 计算统计数据([10, 20, 30, 40, 50])
print(f"平均值: {统计结果['平均值']}")
print(f"最大值: {统计结果['最大值']}")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

使用类和对象返回复杂数据

对于更复杂的数据结构,可以使用自定义类:

class 学生成绩单:
    def __init__(self, 姓名, 成绩列表):
        self.姓名 = 姓名
        self.成绩列表 = 成绩列表
        self.平均分 = sum(成绩列表) / len(成绩列表)
        self.最高分 = max(成绩列表)

def 生成成绩单(姓名, 成绩列表):
    return 学生成绩单(姓名, 成绩列表)

小明成绩单 = 生成成绩单("小明", [85, 92, 78, 90])
print(f"{小明成绩单.姓名}的平均分是{小明成绩单.平均分}")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

Python partial偏函数

偏函数(Partial Function)是Python functools模块中的一个重要功能,它允许我们固定函数的某些参数,从而创建一个新的函数。

基本概念

偏函数的主要用途是:

  • 减少重复代码
  • 提高代码可读性
  • 创建特定场景的专用函数

基本用法

from functools import partial

# 原始函数
def 幂运算(底数, 指数):
    return 底数 ** 指数

# 创建平方函数 - 固定指数为2
平方 = partial(幂运算, 指数=2)

# 创建立方函数 - 固定指数为3
立方 = partial(幂运算, 指数=3)

# 使用偏函数
print(平方(4))  # 输出: 16
print(立方(4))  # 输出: 64
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

实际应用场景

示例1:简化函数调用
from functools import partial

def 格式化打印(内容, 前缀="", 后缀="", 是否换行=True):
    结果 = f"{前缀}{内容}{后缀}"
    if 是否换行:
        print(结果)
    else:
        print(结果, end="")

# 创建特定格式的打印函数
错误打印 = partial(格式化打印, 前缀="错误: ", 后缀="!", 是否换行=True)
警告打印 = partial(格式化打印, 前缀="警告: ", 后缀=".", 是否换行=True)

错误打印("文件不存在")  # 输出: 错误: 文件不存在!
警告打印("磁盘空间不足")  # 输出: 警告: 磁盘空间不足.
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
示例2:配合内置函数
from functools import partial

# 创建一个只接收十进制数的int函数
二进制转十进制 = partial(int, base=2)
十六进制转十进制 = partial(int, base=16)

print(二进制转十进制("1010"))  # 输出: 10
print(十六进制转十进制("1A"))  # 输出: 26
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
示例3:配合排序函数
from functools import partial

学生列表 = [
    {"姓名": "张三", "年龄": 18, "成绩": 85},
    {"姓名": "李四", "年龄": 17, "成绩": 92},
    {"姓名": "王五", "年龄": 19, "成绩": 78}
]

def 按键排序(列表,):
    return sorted(列表, key=lambda x: x[])

按年龄排序 = partial(按键排序,="年龄")
按成绩排序 = partial(按键排序,="成绩")

print("按年龄排序:")
for 学生 in 按年龄排序(学生列表):
    print(f"{学生['姓名']}: {学生['年龄']}岁")

print("\n按成绩排序:")
for 学生 in 按成绩排序(学生列表):
    print(f"{学生['姓名']}: {学生['成绩']}分")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

注意事项

  1. 偏函数不会修改原始函数
  2. 可以固定位置参数和关键字参数
  3. 创建偏函数时未指定的参数在调用时需要提供

从实例出发,攻克Python函数递归

递归是一种函数调用自身的编程技术,适合解决可以分解为相似子问题的任务。

递归的基本结构

一个典型的递归函数包含两个部分:

  1. 基本情况(Base Case) - 不再递归调用的终止条件
  2. 递归情况(Recursive Case) - 函数调用自身的情况
def 递归函数(参数):
    # 基本情况 - 终止递归
    if 终止条件:
        return 基本结果
    
    # 递归情况 - 调用自身
    return 递归函数(新参数)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

示例1:计算阶乘

阶乘是递归的经典应用:

def 阶乘(n):
    # 基本情况
    if n == 0 or n == 1:
        return 1
    
    # 递归情况
    return n * 阶乘(n-1)

print(阶乘(5))  # 输出: 120 (5*4*3*2*1)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

递归过程分析:

阶乘(5) = 5 * 阶乘(4) = 5 * 24 = 120
  阶乘(4) = 4 * 阶乘(3) = 4 * 6 = 24
    阶乘(3) = 3 * 阶乘(2) = 3 * 2 = 6
      阶乘(2) = 2 * 阶乘(1) = 2 * 1 = 2
        阶乘(1) = 1 (基本情况)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

示例2:斐波那契数列

斐波那契数列是另一个递归的经典例子:

def 斐波那契(n):
    # 基本情况
    if n <= 0:
        return 0
    elif n == 1:
        return 1
    
    # 递归情况
    return 斐波那契(n-1) + 斐波那契(n-2)

for i in range(10):
    print(f"斐波那契({i}) = {斐波那契(i)}")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

输出:

斐波那契(0) = 0
斐波那契(1) = 1
斐波那契(2) = 1
斐波那契(3) = 2
斐波那契(4) = 3
斐波那契(5) = 5
斐波那契(6) = 8
斐波那契(7) = 13
斐波那契(8) = 21
斐波那契(9) = 34
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

示例3:递归遍历目录

递归非常适合处理树形结构,如文件系统:

import os

def 列出所有文件(目录, 缩进=0):
    # 打印当前目录名
    print(" " * 缩进 + f"📁 {os.path.basename(目录)}")
    
    # 遍历目录中的所有项目
    for 项目 in os.listdir(目录):
        完整路径 = os.path.join(目录, 项目)
        
        # 如果是目录,递归调用
        if os.path.isdir(完整路径):
            列出所有文件(完整路径, 缩进 + 2)
        else:
            # 如果是文件,直接打印
            print(" " * (缩进 + 2) + f"📄 {项目}")

# 使用示例 (替换为实际路径)
# 列出所有文件("/Users/用户名/文档")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

递归的优化:记忆化

简单递归在处理大规模问题时可能效率低下。以斐波那契数列为例,可以使用记忆化技术优化:

def 优化斐波那契(n, 记忆={}):
    # 检查是否已计算过
    if n in 记忆:
        return 记忆[n]
    
    # 基本情况
    if n <= 0:
        return 0
    elif n == 1:
        return 1
    
    # 递归计算并存储结果
    记忆[n] = 优化斐波那契(n-1, 记忆) + 优化斐波那契(n-2, 记忆)
    return 记忆[n]

# 比较优化前后的性能差异
import time

n = 35

开始时间 = time.time()
结果1 = 斐波那契(n)
结束时间 = time.time()
print(f"普通递归: 斐波那契({n}) = {结果1}, 耗时: {结束时间-开始时间:.2f}秒")

开始时间 = time.time()
结果2 = 优化斐波那契(n)
结束时间 = time.time()
print(f"优化递归: 斐波那契({n}) = {结果2}, 耗时: {结束时间-开始时间:.2f}秒")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.

递归的注意事项

  1. 递归深度限制:Python默认限制递归深度为1000,可以通过sys.setrecursionlimit()修改
  2. 栈溢出风险:过深的递归可能导致栈溢出
  3. 性能考虑:某些情况下,循环可能比递归更高效
  4. 尾递归:在函数的最后一步调用自身的递归,某些语言会进行优化(但Python不会)

何时使用递归

递归特别适合以下场景:

  • 问题可以分解为相似的子问题
  • 数据结构是分层或树形的(如文件系统、XML解析)
  • 回溯算法
  • 分治算法(如快速排序、归并排序)

通过这些实例,你应该能够理解递归的基本原理和应用场景,为解决更复杂的问题打下基础。