Python函数(下)

学习目标

通过本集的学习,你将能够:

  • 使用默认参数简化函数调用
  • 理解可变参数的用法
  • 编写递归函数
  • 理解函数作为一等公民的概念
  • 掌握函数的高级用法

1. 默认参数

默认参数允许在调用函数时省略某些参数,使用预定义的默认值。

1.1 基本用法

# 带默认参数的函数
def greet(name, greeting="Hello"):
    """打招呼,可自定义问候语"""
    print(f"{greeting}, {name}!")

# 使用默认参数
greet("Alice")              # 输出: Hello, Alice!

# 覆盖默认参数
greet("Bob", "Hi")          # 输出: Hi, Bob!
greet("Charlie", "Good morning")  # 输出: Good morning, Charlie!

1.2 多个默认参数

def introduce(name, age=18, city="未知"):
    """介绍个人信息"""
    print(f"我叫{name},今年{age}岁,来自{city}")

introduce("张三")                    # 使用所有默认值
introduce("李四", 25)               # 覆盖age
introduce("王五", city="北京")      # 只覆盖city,age用默认值
introduce("赵六", 30, "上海")       # 覆盖所有参数

1.3 默认参数的注意事项

# 注意:默认参数在函数定义时计算
# 避免使用可变对象作为默认参数

# 错误示例
def bad_append(item, my_list=[]):
    my_list.append(item)
    return my_list

print(bad_append(1))  # 输出: [1]
print(bad_append(2))  # 输出: [1, 2]  (问题:列表被重用了)
print(bad_append(3))  # 输出: [1, 2, 3]

# 正确示例
def good_append(item, my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(item)
    return my_list

print(good_append(1))  # 输出: [1]
print(good_append(2))  # 输出: [2]
print(good_append(3))  # 输出: [3]

2. 可变参数

可变参数允许函数接受任意数量的参数。

2.1 *args:任意数量的位置参数

# *args 收集多个参数为一个元组
def sum_all(*args):
    """计算所有参数的和"""
    total = 0
    for num in args:
        total += num
    return total

print(sum_all(1, 2))          # 输出: 3
print(sum_all(1, 2, 3, 4))    # 输出: 10
print(sum_all(10, 20, 30))    # 输出: 60

def print_args(*args):
    """打印所有参数"""
    print("参数类型:", type(args))
    print("参数内容:", args)
    for i, arg in enumerate(args):
        print(f"参数{i}: {arg}")

print_args("a", "b", "c")

ASCII图:*args 的工作原理

调用: sum_all(1, 2, 3, 4)
        │
        ▼
   ┌─────────────────┐
   │  1, 2, 3, 4    │
   │  打包成元组     │
   │  (1, 2, 3, 4)  │
   └─────────────────┘
        │
        ▼
   在函数中作为 args 使用

2.2 **kwargs:任意数量的关键字参数

# **kwargs 收集多个关键字参数为一个字典
def print_info(**kwargs):
    """打印关键字参数"""
    print("参数类型:", type(kwargs))
    print("参数内容:", kwargs)
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=25, city="北京")

def build_person(name, **kwargs):
    """构建人物信息字典"""
    person = {"name": name}
    for key, value in kwargs.items():
        person[key] = value
    return person

person1 = build_person("张三", age=30, job="工程师")
person2 = build_person("李四", age=25, city="上海", hobby="读书")
print(person1)
print(person2)

2.3 混合使用

def func(a, b, *args, **kwargs):
    """混合使用各种参数"""
    print("a =", a)
    print("b =", b)
    print("args =", args)
    print("kwargs =", kwargs)

func(1, 2, 3, 4, 5, x=10, y=20)
# 输出:
# a = 1
# b = 2
# args = (3, 4, 5)
# kwargs = {'x': 10, 'y': 20}

2.4 解包参数

# 使用 * 解包列表/元组
def add(a, b, c):
    return a + b + c

numbers = [1, 2, 3]
print(add(*numbers))  # 等同于 add(1, 2, 3)

# 使用 ** 解包字典
def greet(name, greeting):
    print(f"{greeting}, {name}!")

info = {"name": "Alice", "greeting": "Hello"}
greet(**info)  # 等同于 greet(name="Alice", greeting="Hello")

3. 递归函数

递归函数是调用自身的函数。

3.1 递归的基本概念

递归 = 基线条件 + 递归条件

    递归调用
       │
       ▼
    f(n) ──→ f(n-1) ──→ f(n-2) ──→ ... ──→ f(1) ──→ 基线条件
       │          │          │                  │
       └──────────┴──────────┴──────────────────┘
              返回值向上传递

3.2 阶乘的递归实现

def factorial(n):
    """计算阶乘(递归实现)"""
    # 基线条件:0! = 1, 1! = 1
    if n == 0 or n == 1:
        return 1
    # 递归条件:n! = n * (n-1)!
    else:
        return n * factorial(n - 1)

print(factorial(5))  # 输出: 120
print(factorial(0))  # 输出: 1
print(factorial(10)) # 输出: 3628800

# 非递归实现(对比)
def factorial_iterative(n):
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result

阶乘递归调用流程:

factorial(5)
    │
    ├─→ 5 * factorial(4)
    │         │
    │         ├─→ 4 * factorial(3)
    │         │         │
    │         │         ├─→ 3 * factorial(2)
    │         │         │         │
    │         │         │         ├─→ 2 * factorial(1)
    │         │         │         │         │
    │         │         │         │         └─→ 1
    │         │         │         │
    │         │         │         └─→ 2 * 1 = 2
    │         │         │
    │         │         └─→ 3 * 2 = 6
    │         │
    │         └─→ 4 * 6 = 24
    │
    └─→ 5 * 24 = 120

3.3 斐波那契数列的递归实现

def fibonacci(n):
    """斐波那契数列(递归实现)"""
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci(n - 1) + fibonacci(n - 2)

# 打印前10项
for i in range(10):
    print(fibonacci(i), end=" ")
# 输出: 0 1 1 2 3 5 8 13 21 34

3.4 递归的注意事项

# Python有递归深度限制
import sys
print("默认递归深度限制:", sys.getrecursionlimit())  # 通常是 1000

# 可以修改(但不推荐)
sys.setrecursionlimit(2000)

# 递归过深会导致栈溢出
try:
    factorial(2000)
except RecursionError:
    print("递归深度溢出!")

4. 函数作为一等公民

在Python中,函数是一等公民,可以像其他数据类型一样使用。

4.1 函数赋值给变量

def greet(name):
    return f"Hello, {name}!"

# 函数赋值给变量
say_hello = greet
print(say_hello("Alice"))  # 输出: Hello, Alice!

4.2 函数作为参数

def add(a, b):
    return a + b

def multiply(a, b):
    return a * b

def apply_operation(func, x, y):
    """接受一个函数作为参数"""
    return func(x, y)

print(apply_operation(add, 3, 5))       # 输出: 8
print(apply_operation(multiply, 3, 5))  # 输出: 15

4.3 函数作为返回值

def make_multiplier(n):
    """返回一个乘法函数"""
    def multiplier(x):
        return x * n
    return multiplier

times2 = make_multiplier(2)
times3 = make_multiplier(3)

print(times2(5))   # 输出: 10
print(times3(5))   # 输出: 15

4.4 lambda 函数(匿名函数)

# 简单的lambda函数
square = lambda x: x * x
print(square(5))  # 输出: 25

# 带多个参数的lambda
add = lambda a, b: a + b
print(add(3, 5))  # 输出: 8

# 与sorted配合使用
students = [
    {"name": "Alice", "age": 25},
    {"name": "Bob", "age": 20},
    {"name": "Charlie", "age": 30}
]

# 按年龄排序
students_sorted = sorted(students, key=lambda s: s["age"])
print(students_sorted)

5. 实用案例

5.1 案例1:递归实现二分查找

# binary_search.py

def binary_search(arr, target, low=0, high=None):
    """二分查找(递归实现)"""
    if high is None:
        high = len(arr) - 1
    
    # 基线条件:未找到
    if low > high:
        return -1
    
    mid = (low + high) // 2
    
    # 找到目标
    if arr[mid] == target:
        return mid
    # 目标在左半部分
    elif arr[mid] > target:
        return binary_search(arr, target, low, mid - 1)
    # 目标在右半部分
    else:
        return binary_search(arr, target, mid + 1, high)

# 测试
numbers = [1, 3, 5, 7, 9, 11, 13, 15]
print(binary_search(numbers, 7))   # 输出: 3
print(binary_search(numbers, 10))  # 输出: -1
print(binary_search(numbers, 1))   # 输出: 0

5.2 案例2:函数装饰器

# decorator.py

import time

def timer(func):
    """计时装饰器"""
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 执行时间: {end - start:.4f}秒")
        return result
    return wrapper

@timer
def slow_function():
    """一个慢函数"""
    time.sleep(1)
    print("函数执行完成")

@timer
def factorial(n):
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result

slow_function()
print(factorial(1000))

5.3 案例3:计算器(使用函数式编程)

# functional_calculator.py

def add(a, b): return a + b
def subtract(a, b): return a - b
def multiply(a, b): return a * b
def divide(a, b): return a / b if b != 0 else "错误"

# 操作字典
operations = {
    "+": add,
    "-": subtract,
    "*": multiply,
    "/": divide
}

def calculator():
    print("函数式计算器")
    print("可用操作:", ", ".join(operations.keys()))
    
    while True:
        expr = input("请输入表达式 (如 3 + 5,输入 q 退出): ")
        if expr.lower() == 'q':
            break
        
        try:
            a, op, b = expr.split()
            a = float(a)
            b = float(b)
            
            if op in operations:
                result = operations[op](a, b)
                print(f"结果: {result}")
            else:
                print("未知操作符")
        except:
            print("输入格式错误,请重试")

calculator()

6. 自测问题

  1. 默认参数的值在什么时候计算?
  2. *args 和 **kwargs 的区别是什么?
  3. 递归函数必须包含什么?
  4. 什么是函数作为一等公民?
  5. lambda 函数的特点是什么?

7. 下集预告

下一集我们将学习Python的列表与元组!

参考资料

« 上一篇 Python函数(上) 下一篇 » Python列表与元组