前言:函数化编程的重要性

在前九篇文章中,我们系统学习了Python的基本语法、数据类型、控制结构、文件操作以及数据结构。现在,我们将深入探讨Python编程中最为重要的概念之一——函数。函数是组织代码的基本单元,它们允许我们将代码分解为可重用的块,提高代码的可读性、可维护性和复用性。

函数不仅是代码组织的工具,更是抽象思维的体现。通过函数,我们可以将复杂问题分解为更小、更易管理的部分,每个部分都有明确的输入和输出。本文将深入探讨Python函数的定义、参数传递机制以及高级函数特性,通过丰富的实战案例,帮助你掌握函数编程的精髓。


一、 函数基础:定义与调用

函数是一段可重用的代码块,它接受输入(参数),执行特定任务,并返回结果。

1.1 函数的基本结构

语法结构:

def function_name(parameters):
    """文档字符串(可选)"""
    # 函数体
    statement1
    statement2
    ...
    return result  # 可选

实战案例10-1:基本函数定义与调用

# 定义一个简单的函数
def greet():
    """打印问候语"""
    print("Hello, World!")

# 调用函数
greet()  # 输出: Hello, World!

# 带参数的函数
def greet_person(name):
    """向指定的人问候"""
    print(f"Hello, {name}!")

greet_person("Alice")  # 输出: Hello, Alice!
greet_person("Bob")    # 输出: Hello, Bob!

# 带返回值的函数
def add_numbers(a, b):
    """返回两个数的和"""
    return a + b

result = add_numbers(5, 3)
print(f"5 + 3 = {result}")  # 输出: 5 + 3 = 8

# 多个返回值的函数(实际上返回元组)
def get_name_and_age():
    """返回姓名和年龄"""
    return "Alice", 25  # 实际上是返回一个元组

name, age = get_name_and_age()  # 元组解包
print(f"Name: {name}, Age: {age}")  # 输出: Name: Alice, Age: 25

# 无返回值的函数实际上返回None
def do_nothing():
    """什么都不做"""
    pass

result = do_nothing()
print(f"无返回值函数的返回结果: {result}")  # 输出: 无返回值函数的返回结果: None

1.2 文档字符串(Docstring)

文档字符串是函数的第一条语句,用于描述函数的功能、参数和返回值。

实战案例10-2:文档字符串的使用

def calculate_circle_area(radius):
    """
    计算圆的面积
    
    参数:
    radius (float): 圆的半径,必须为非负数
    
    返回:
    float: 圆的面积
    
    抛出:
    ValueError: 如果半径为负数
    """
    if radius < 0:
        raise ValueError("半径不能为负数")
    return 3.14159 * radius ** 2

# 查看文档字符串
print(calculate_circle_area.__doc__)

# 使用help函数查看文档
help(calculate_circle_area)

# 测试函数
try:
    area = calculate_circle_area(5)
    print(f"半径为5的圆面积: {area:.2f}")  # 输出: 半径为5的圆面积: 78.54
    
    area = calculate_circle_area(-2)  # 会抛出异常
except ValueError as e:
    print(f"错误: {e}")  # 输出: 错误: 半径不能为负数

1.3 函数的作用域

Python中有四种作用域:

  1. 局部作用域(Local):函数内部
  2. 闭包函数外的函数作用域(Enclosing):嵌套函数的外部函数
  3. 全局作用域(Global):模块级别
  4. 内置作用域(Built-in):Python内置名称

实战案例10-3:作用域解析

# 全局变量
global_var = "我是全局变量"

def test_scope():
    # 局部变量
    local_var = "我是局部变量"
    print(f"函数内部 - 局部变量: {local_var}")
    print(f"函数内部 - 全局变量: {global_var}")
    
    # 尝试修改全局变量(实际上会创建新的局部变量)
    global_var = "我试图修改全局变量"  # 这实际上是创建了一个新的局部变量
    print(f"函数内部 - 修改后的变量: {global_var}")
    
    def inner_function():
        # 内部函数可以访问外部函数的变量
        print(f"内部函数 - 外部函数的变量: {local_var}")
        print(f"内部函数 - 全局变量: {global_var}")
    
    inner_function()

test_scope()
print(f"函数外部 - 全局变量: {global_var}")  # 全局变量没有被修改

# 使用global关键字修改全局变量
def modify_global():
    global global_var  # 声明使用全局变量
    global_var = "我真的修改了全局变量"
    print(f"函数内部 - 修改后的全局变量: {global_var}")

modify_global()
print(f"函数外部 - 修改后的全局变量: {global_var}")  # 全局变量被修改了

# 使用nonlocal关键字修改嵌套作用域的变量
def outer_function():
    outer_var = "外部函数变量"
    
    def inner_function():
        nonlocal outer_var  # 声明使用外部函数的变量
        outer_var = "内部函数修改了外部变量"
        print(f"内部函数 - 修改后的变量: {outer_var}")
    
    inner_function()
    print(f"外部函数 - 修改后的变量: {outer_var}")

outer_function()

二、 参数传递:位置参数与默认参数

Python支持多种参数传递方式,使函数调用更加灵活。

2.1 位置参数(Positional Arguments)

位置参数是按照定义时的顺序传递的参数。

实战案例10-4:位置参数的使用

def describe_pet(animal_type, pet_name):
    """显示宠物信息"""
    print(f"I have a {animal_type}.")
    print(f"My {animal_type}'s name is {pet_name}.")

# 按位置传递参数
describe_pet("dog", "Willie")  # 正确顺序
describe_pet("Willie", "dog")  # 错误顺序,但语法正确,语义错误

# 多次调用函数
describe_pet("hamster", "Harry")
describe_pet("cat", "Whiskers")

# 带有更多参数的函数
def build_profile(first, last, age, city):
    """构建用户资料字典"""
    profile = {
        "first_name": first,
        "last_name": last,
        "age": age,
        "city": city
    }
    return profile

user_profile = build_profile("Alice", "Smith", 25, "New York")
print(f"用户资料: {user_profile}")

2.2 默认参数(Default Arguments)

默认参数是在定义函数时指定默认值的参数,调用时可以省略。

实战案例10-5:默认参数的使用

def describe_pet(pet_name, animal_type="dog"):
    """显示宠物信息(带有默认参数)"""
    print(f"I have a {animal_type}.")
    print(f"My {animal_type}'s name is {pet_name}.")

# 使用默认参数
describe_pet("Willie")  # 使用默认的animal_type="dog"
describe_pet("Harry", "hamster")  # 提供animal_type参数

# 多个默认参数
def make_shirt(size="large", message="I love Python"):
    """制作T恤"""
    print(f"Making a {size} shirt with the message: '{message}'")

make_shirt()  # 使用所有默认值
make_shirt("medium")  # 提供size,使用默认message
make_shirt(message="Hello World")  # 使用默认size,提供message
make_shirt("small", "Coding is fun!")  # 提供所有参数

# 默认参数的注意事项
def add_to_list(value, my_list=[]):
    """向列表添加元素(有问题的实现)"""
    my_list.append(value)
    return my_list

# 默认参数在函数定义时计算,而不是每次调用时
result1 = add_to_list(1)
print(f"第一次调用: {result1}")  # [1]

result2 = add_to_list(2)
print(f"第二次调用: {result2}")  # [1, 2] - 这不是我们期望的!

# 正确的实现方式
def add_to_list_correct(value, my_list=None):
    """向列表添加元素(正确的实现)"""
    if my_list is None:
        my_list = []
    my_list.append(value)
    return my_list

result1 = add_to_list_correct(1)
print(f"第一次调用: {result1}")  # [1]

result2 = add_to_list_correct(2)
print(f"第二次调用: {result2}")  # [2] - 这才是我们期望的!

2.3 关键字参数(Keyword Arguments)

关键字参数是通过参数名传递的参数,可以不按照定义顺序。

实战案例10-6:关键字参数的使用

def describe_pet(animal_type, pet_name):
    """显示宠物信息"""
    print(f"I have a {animal_type}.")
    print(f"My {animal_type}'s name is {pet_name}.")

# 使用关键字参数
describe_pet(animal_type="hamster", pet_name="Harry")
describe_pet(pet_name="Willie", animal_type="dog")  # 顺序不重要

# 混合使用位置参数和关键字参数
describe_pet("cat", pet_name="Whiskers")  # 位置参数必须在关键字参数之前

# 以下代码会报错
# describe_pet(animal_type="bird", "Polly")  # 关键字参数后不能有位置参数

# 更复杂的例子
def create_user_profile(first_name, last_name, age=30, city="Unknown", country="Unknown"):
    """创建用户资料"""
    profile = {
        "first_name": first_name,
        "last_name": last_name,
        "age": age,
        "city": city,
        "country": country
    }
    return profile

# 使用关键字参数提供部分信息
profile1 = create_user_profile("Alice", "Smith", age=25, city="New York")
print(f"用户1资料: {profile1}")

# 使用关键字参数提供所有信息
profile2 = create_user_profile(
    first_name="Bob",
    last_name="Johnson",
    age=35,
    city="London",
    country="UK"
)
print(f"用户2资料: {profile2}")

# 只提供必需参数
profile3 = create_user_profile("Charlie", "Brown")
print(f"用户3资料: {profile3}")

三、 高级参数传递:可变参数

Python支持可变数量的参数,使函数更加灵活。

*3.1 可变位置参数(args)

使用*args可以接收任意数量的位置参数。

实战案例10-7:可变位置参数的使用

def make_pizza(*toppings):
    """制作披萨,接受任意数量的配料"""
    print("\nMaking a pizza with the following toppings:")
    for topping in toppings:
        print(f"- {topping}")

# 使用不同数量的参数调用函数
make_pizza("pepperoni")
make_pizza("mushrooms", "green peppers", "extra cheese")

# 与其他参数结合使用
def make_pizza_size(size, *toppings):
    """制作指定大小的披萨"""
    print(f"\nMaking a {size} pizza with the following toppings:")
    for topping in toppings:
        print(f"- {topping}")

make_pizza_size("large", "pepperoni")
make_pizza_size("medium", "mushrooms", "olives", "onions")

# 使用*args收集剩余的位置参数
def print_args(arg1, arg2, *args):
    """演示*args的使用"""
    print(f"第一个参数: {arg1}")
    print(f"第二个参数: {arg2}")
    print(f"其余参数: {args}")  # 这是一个元组

print_args(1, 2, 3, 4, 5)  # 输出: 第一个参数: 1, 第二个参数: 2, 其余参数: (3, 4, 5)

# 实际应用:计算任意数量的数字之和
def sum_numbers(*numbers):
    """计算任意数量的数字之和"""
    total = 0
    for num in numbers:
        total += num
    return total

print(f"1+2+3 = {sum_numbers(1, 2, 3)}")  # 6
print(f"1+2+3+4+5 = {sum_numbers(1, 2, 3, 4, 5)}")  # 15
print(f"空参数 = {sum_numbers()}")  # 0

# 使用*运算符解包序列
numbers = [1, 2, 3, 4, 5]
print(f"列表求和: {sum_numbers(*numbers)}")  # 15

tuple_numbers = (10, 20, 30)
print(f"元组求和: {sum_numbers(*tuple_numbers)}")  # 60

**3.2 可变关键字参数(kwargs)

使用**kwargs可以接收任意数量的关键字参数。

实战案例10-8:可变关键字参数的使用

def build_profile(first, last, **user_info):
    """构建用户资料,接受任意数量的关键字参数"""
    profile = {}
    profile['first_name'] = first
    profile['last_name'] = last
    
    for key, value in user_info.items():
        profile[key] = value
    
    return profile

# 使用不同数量的关键字参数
user_profile = build_profile(
    "albert", 
    "einstein",
    location="princeton",
    field="physics",
    age=76
)
print(f"用户资料: {user_profile}")

# 与其他参数结合使用
def create_car(make, model, **car_info):
    """创建汽车信息"""
    car = {"make": make, "model": model}
    car.update(car_info)
    return car

car = create_car(
    "subaru", 
    "outback",
    color="blue",
    tow_package=True,
    year=2023
)
print(f"汽车信息: {car}")

# 使用**kwargs收集剩余的关键字参数
def print_kwargs(arg1, arg2, **kwargs):
    """演示**kwargs的使用"""
    print(f"第一个参数: {arg1}")
    print(f"第二个参数: {arg2}")
    print(f"关键字参数: {kwargs}")  # 这是一个字典

print_kwargs(1, 2, name="Alice", age=25, city="New York")

# 实际应用:配置函数
def configure_app(**settings):
    """配置应用程序"""
    default_settings = {
        "debug": False,
        "log_level": "INFO",
        "max_connections": 100
    }
    
    # 更新默认设置
    default_settings.update(settings)
    return default_settings

# 使用不同配置
app_config = configure_app()
print(f"默认配置: {app_config}")

app_config = configure_app(debug=True, max_connections=200)
print(f"自定义配置: {app_config}")

# 使用**运算符解包字典
settings_dict = {"debug": True, "log_level": "DEBUG", "timeout": 30}
app_config = configure_app(**settings_dict)
print(f"字典解包配置: {app_config}")

3.3 综合使用所有参数类型

Python允许在函数定义中综合使用所有参数类型,但必须遵循特定顺序。

参数顺序规则:

  1. 位置参数
  2. 默认参数
  3. 可变位置参数(*args)
  4. 关键字-only参数(Python 3+)
  5. 可变关键字参数(**kwargs)

实战案例10-9:综合参数使用

def complex_function(a, b=10, *args, c=20, d=30, **kwargs):
    """
    综合使用所有参数类型的复杂函数
    
    参数:
    a: 必需的位置参数
    b: 有默认值的位置参数
    *args: 可变位置参数
    c: 关键字-only参数(有默认值)
    d: 关键字-only参数(有默认值)
    **kwargs: 可变关键字参数
    """
    print(f"a = {a}")
    print(f"b = {b}")
    print(f"args = {args}")
    print(f"c = {c}")
    print(f"d = {d}")
    print(f"kwargs = {kwargs}")
    print("-" * 30)

# 测试各种调用方式
complex_function(1)  # a=1, b=10, args=(), c=20, d=30, kwargs={}
complex_function(1, 2)  # a=1, b=2, args=(), c=20, d=30, kwargs={}
complex_function(1, 2, 3, 4, 5)  # a=1, b=2, args=(3,4,5), c=20, d=30, kwargs={}
complex_function(1, 2, 3, 4, 5, c=100, d=200)  # a=1, b=2, args=(3,4,5), c=100, d=200, kwargs={}
complex_function(1, 2, 3, 4, 5, c=100, d=200, x=999, y=888)  # a=1, b=2, args=(3,4,5), c=100, d=200, kwargs={'x':999,'y':888}

# 关键字-only参数(Python 3+)
def keyword_only_function(a, b, *, c, d):
    """使用关键字-only参数"""
    print(f"a={a}, b={b}, c={c}, d={d}")

# 必须使用关键字传递c和d
keyword_only_function(1, 2, c=3, d=4)  # 正确
# keyword_only_function(1, 2, 3, 4)  # 错误:必须使用关键字参数

# 实际应用:灵活的数据库查询函数
def query_database(table, *columns, where=None, order_by=None, limit=100, **filters):
    """
    模拟数据库查询函数
    
    参数:
    table: 表名(必需)
    *columns: 要查询的列
    where: WHERE条件(关键字-only)
    order_by: 排序字段(关键字-only)
    limit: 限制结果数量(关键字-only)
    **filters: 其他过滤条件
    """
    query = f"SELECT {', '.join(columns) if columns else '*'} FROM {table}"
    
    conditions = []
    if where:
        conditions.append(where)
    
    for key, value in filters.items():
        conditions.append(f"{key} = {value}")
    
    if conditions:
        query += " WHERE " + " AND ".join(conditions)
    
    if order_by:
        query += f" ORDER BY {order_by}"
    
    if limit:
        query += f" LIMIT {limit}"
    
    return query

# 使用各种参数组合进行查询
print(query_database("users", "id", "name", "email", where="age > 18", limit=10))
print(query_database("products", "name", "price", category="electronics", in_stock=True))
print(query_database("orders", where="status = 'completed'", order_by="created_at DESC", limit=50))

四、 函数高级特性

Python函数支持许多高级特性,如 lambda 函数、闭包和装饰器等。

4.1 Lambda 函数(匿名函数)

Lambda函数是一种简洁的定义简单函数的方式。

实战案例10-10:Lambda函数的使用

# 基本的lambda函数
add = lambda x, y: x + y
print(f"5 + 3 = {add(5, 3)}")  # 8

# 与内置函数结合使用
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 使用lambda过滤偶数
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(f"偶数: {even_numbers}")  # [2, 4, 6, 8, 10]

# 使用lambda映射平方数
squared_numbers = list(map(lambda x: x ** 2, numbers))
print(f"平方数: {squared_numbers}")  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 使用lambda排序
pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
pairs.sort(key=lambda pair: pair[1])  # 按第二个元素排序
print(f"按字母排序: {pairs}")  # [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]

# 在GUI编程中的使用(模拟)
def create_button(text, on_click):
    """模拟创建按钮"""
    print(f"创建按钮: '{text}'")
    print("模拟点击按钮...")
    on_click()

# 使用lambda作为回调函数
create_button("点击我", lambda: print("按钮被点击了!"))

# 多个参数的lambda
multiply = lambda x, y, z: x * y * z
print(f"2 * 3 * 4 = {multiply(2, 3, 4)}")  # 24

# 立即执行的lambda函数
result = (lambda x: x ** 2)(5)
print(f"立即执行的结果: {result}")  # 25

4.2 闭包(Closure)

闭包是引用了外部函数变量的内部函数。

实战案例10-11:闭包的使用

def outer_function(msg):
    """外部函数"""
    message = msg
    
    def inner_function():
        """内部函数(闭包)"""
        print(message)  # 引用外部函数的变量
    
    return inner_function

# 创建闭包
hello_func = outer_function("Hello")
goodbye_func = outer_function("Goodbye")

# 调用闭包
hello_func()    # 输出: Hello
goodbye_func()  # 输出: Goodbye

# 更实用的例子:计数器
def counter():
    """创建计数器"""
    count = 0
    
    def increment():
        nonlocal count  # 使用外部变量
        count += 1
        return count
    
    return increment

# 创建两个独立的计数器
counter1 = counter()
counter2 = counter()

print(f"计数器1: {counter1()}")  # 1
print(f"计数器1: {counter1()}")  # 2
print(f"计数器2: {counter2()}")  # 1
print(f"计数器1: {counter1()}")  # 3
print(f"计数器2: {counter2()}")  # 2

# 闭包在实际中的应用:配置函数
def configurator(initial_config):
    """创建配置管理器"""
    config = initial_config.copy()
    
    def get(key):
        return config.get(key)
    
    def set(key, value):
        config[key] = value
        return config
    
    def update(new_config):
        config.update(new_config)
        return config
    
    # 返回多个函数
    return get, set, update

# 使用配置管理器
get_config, set_config, update_config = configurator({
    "debug": False,
    "log_level": "INFO"
})

print(f"初始日志级别: {get_config('log_level')}")  # INFO
set_config("log_level", "DEBUG")
print(f"更新后的日志级别: {get_config('log_level')}")  # DEBUG

update_config({"max_connections": 100, "timeout": 30})
print(f"所有配置: {get_config('_')}")  # 需要修改get函数来支持返回所有配置

4.3 装饰器(Decorator)基础

装饰器是一种修改函数行为的特殊函数。

实战案例10-12:装饰器的使用

# 简单的装饰器
def simple_decorator(func):
    """简单的装饰器"""
    def wrapper():
        print("函数执行前")
        result = func()
        print("函数执行后")
        return result
    return wrapper

@simple_decorator
def say_hello():
    """问候函数"""
    print("Hello!")

# 使用装饰器
say_hello()
# 输出:
# 函数执行前
# Hello!
# 函数执行后

# 带参数的装饰器
def repeat(n):
    """重复执行函数的装饰器"""
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(n):
                print(f"第 {i+1} 次执行:")
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    """问候指定的人"""
    print(f"Hello, {name}!")

greet("Alice")
# 输出:
# 第 1 次执行:
# Hello, Alice!
# 第 2 次执行:
# Hello, Alice!
# 第 3 次执行:
# Hello, Alice!

# 实用的装饰器:计时器
import time

def timer(func):
    """计算函数执行时间的装饰器"""
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"函数 {func.__name__} 执行时间: {end_time - start_time:.6f} 秒")
        return result
    return wrapper

@timer
def slow_function():
    """模拟耗时函数"""
    time.sleep(1)
    return "完成"

result = slow_function()  # 输出: 函数 slow_function 执行时间: 1.000000 秒

# 保留原函数的元信息
def preserve_metadata(func):
    """保留函数元信息的装饰器"""
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    wrapper.__name__ = func.__name__
    wrapper.__doc__ = func.__doc__
    return wrapper

# 使用functools.wraps更简单
from functools import wraps

def better_decorator(func):
    """更好的装饰器(保留元信息)"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("装饰器逻辑")
        return func(*args, **kwargs)
    return wrapper

@better_decorator
def documented_function():
    """这是一个有文档的函数"""
    print("函数执行")

print(f"函数名: {documented_function.__name__}")  # documented_function
print(f"文档: {documented_function.__doc__}")     # 这是一个有文档的函数

五、 综合实战:数据分析管道

现在,让我们创建一个综合性的数据分析管道,应用本章所学的函数知识。

项目目标:

  • 使用函数构建数据处理管道
  • 应用各种参数传递技巧
  • 使用装饰器添加功能(如日志、计时)
  • 实现可配置的数据处理流程
  • 提供灵活的数据分析功能

代码实现:

# 数据分析管道系统
def data_analysis_pipeline():
    """数据分析管道主函数"""
    # 示例数据
    data = [
        {"name": "Alice", "age": 25, "score": 85, "department": "Engineering"},
        {"name": "Bob", "age": 30, "score": 92, "department": "Marketing"},
        {"name": "Charlie", "age": 35, "score": 78, "department": "Engineering"},
        {"name": "Diana", "age": 28, "score": 95, "department": "Sales"},
        {"name": "Eve", "age": 32, "score": 88, "department": "Engineering"},
        {"name": "Frank", "age": 40, "score": 76, "department": "Marketing"},
        {"name": "Grace", "age": 27, "score": 91, "department": "Sales"},
        {"name": "Henry", "age": 45, "score": 83, "department": "Engineering"}
    ]
    
    # 定义处理函数
    def load_data():
        """加载数据"""
        print("加载数据...")
        return data
    
    @timer
    def filter_data(data, **filters):
        """过滤数据"""
        print("过滤数据...")
        filtered_data = data
        
        for key, value in filters.items():
            if key == "min_age":
                filtered_data = [item for item in filtered_data if item["age"] >= value]
            elif key == "max_age":
                filtered_data = [item for item in filtered_data if item["age"] <= value]
            elif key == "min_score":
                filtered_data = [item for item in filtered_data if item["score"] >= value]
            elif key == "department":
                filtered_data = [item for item in filtered_data if item["department"] == value]
        
        print(f"过滤后剩余 {len(filtered_data)} 条记录")
        return filtered_data
    
    def transform_data(data, *transformations):
        """转换数据"""
        print("转换数据...")
        transformed_data = data.copy()
        
        for transformation in transformations:
            if transformation == "add_grade":
                for item in transformed_data:
                    score = item["score"]
                    if score >= 90:
                        item["grade"] = "A"
                    elif score >= 80:
                        item["grade"] = "B"
                    elif score >= 70:
                        item["grade"] = "C"
                    else:
                        item["grade"] = "D"
            
            elif transformation == "add_age_group":
                for item in transformed_data:
                    age = item["age"]
                    if age < 30:
                        item["age_group"] = "Young"
                    elif age < 40:
                        item["age_group"] = "Middle"
                    else:
                        item["age_group"] = "Senior"
        
        return transformed_data
    
    def analyze_data(data, *analyses, **options):
        """分析数据"""
        print("分析数据...")
        results = {}
        
        for analysis in analyses:
            if analysis == "average_score":
                total = sum(item["score"] for item in data)
                results["average_score"] = total / len(data)
            
            elif analysis == "department_stats":
                dept_stats = {}
                for item in data:
                    dept = item["department"]
                    if dept not in dept_stats:
                        dept_stats[dept] = {"count": 0, "total_score": 0}
                    
                    dept_stats[dept]["count"] += 1
                    dept_stats[dept]["total_score"] += item["score"]
                
                for dept, stats in dept_stats.items():
                    stats["average_score"] = stats["total_score"] / stats["count"]
                
                results["department_stats"] = dept_stats
            
            elif analysis == "age_score_correlation":
                # 简化的相关性计算
                ages = [item["age"] for item in data]
                scores = [item["score"] for item in data]
                
                # 使用numpy会更好,但这里使用简单实现
                mean_age = sum(ages) / len(ages)
                mean_score = sum(scores) / len(scores)
                
                numerator = sum((age - mean_age) * (score - mean_score) for age, score in zip(ages, scores))
                denominator = (sum((age - mean_age) ** 2 for age in ages) * 
                              sum((score - mean_score) ** 2 for score in scores)) ** 0.5
                
                if denominator != 0:
                    results["age_score_correlation"] = numerator / denominator
                else:
                    results["age_score_correlation"] = 0
        
        return results
    
    def format_results(results, format_type="text"):
        """格式化结果"""
        print("格式化结果...")
        
        if format_type == "text":
            output = []
            for key, value in results.items():
                if key == "average_score":
                    output.append(f"平均分数: {value:.2f}")
                elif key == "department_stats":
                    output.append("部门统计:")
                    for dept, stats in value.items():
                        output.append(f"  {dept}: {stats['count']}人, 平均分: {stats['average_score']:.2f}")
                elif key == "age_score_correlation":
                    output.append(f"年龄与分数相关性: {value:.3f}")
            
            return "\n".join(output)
        
        elif format_type == "json":
            import json
            return json.dumps(results, indent=2)
        
        else:
            return str(results)
    
    # 构建处理管道
    def process_pipeline(**config):
        """数据处理管道"""
        print("=" * 50)
        print("开始数据处理管道")
        print("=" * 50)
        
        # 加载数据
        raw_data = load_data()
        
        # 过滤数据
        filtered_data = filter_data(
            raw_data,
            min_age=config.get("min_age", 0),
            max_age=config.get("max_age", 100),
            min_score=config.get("min_score", 0),
            department=config.get("department", None)
        )
        
        # 转换数据
        transformed_data = transform_data(
            filtered_data,
            *config.get("transformations", [])
        )
        
        # 分析数据
        analysis_results = analyze_data(
            transformed_data,
            *config.get("analyses", []),
            **config.get("analysis_options", {})
        )
        
        # 格式化结果
        formatted_results = format_results(
            analysis_results,
            format_type=config.get("format", "text")
        )
        
        print("=" * 50)
        print("数据处理管道完成")
        print("=" * 50)
        
        return formatted_results
    
    # 运行不同配置的管道
    print("运行数据分析管道...")
    
    # 配置1:基本分析
    config1 = {
        "analyses": ["average_score"],
        "format": "text"
    }
    
    result1 = process_pipeline(**config1)
    print("\n配置1结果:")
    print(result1)
    
    # 配置2:部门统计
    config2 = {
        "analyses": ["department_stats"],
        "format": "text"
    }
    
    result2 = process_pipeline(**config2)
    print("\n配置2结果:")
    print(result2)
    
    # 配置3:复杂分析
    config3 = {
        "min_age": 30,
        "max_age": 40,
        "min_score": 80,
        "transformations": ["add_grade", "add_age_group"],
        "analyses": ["average_score", "department_stats", "age_score_correlation"],
        "format": "text"
    }
    
    result3 = process_pipeline(**config3)
    print("\n配置3结果:")
    print(result3)
    
    # 配置4:JSON格式输出
    config4 = {
        "department": "Engineering",
        "analyses": ["average_score", "department_stats"],
        "format": "json"
    }
    
    result4 = process_pipeline(**config4)
    print("\n配置4结果:")
    print(result4)

# 运行数据分析管道
if __name__ == "__main__":
    data_analysis_pipeline()

总结与展望

通过本篇文章的深入学习,我们全面掌握了Python中的函数定义与参数传递:

  1. 函数基础

    • 掌握了函数的基本定义和调用方法
    • 学会了使用文档字符串描述函数功能
    • 理解了函数作用域和变量访问规则
  2. 参数传递

    • 掌握了位置参数和默认参数的使用
    • 学会了关键字参数和可变参数的使用
    • 理解了参数传递的顺序规则和最佳实践
  3. 高级函数特性

    • 掌握了lambda函数的使用场景
    • 学会了闭包的创建和应用
    • 理解了装饰器的原理和使用方法
  4. 综合应用

    • 通过数据分析管道项目,将所学知识融会贯通
    • 学会了如何构建灵活的数据处理系统
    • 实现了完整的函数化编程解决方案

函数是Python编程的核心概念,掌握好函数定义和参数传递技巧,对于编写高质量、可维护的Python代码至关重要。函数化编程不仅是一种技术,更是一种思维方式,它帮助我们构建更加模块化、可测试和可重用的代码。

思考题:

  1. 在什么情况下应该使用默认参数?使用默认参数时需要注意什么?
  2. *args**kwargs有什么区别?它们各自适用于什么场景?
  3. 闭包和普通函数有什么区别?在什么情况下应该使用闭包?
  4. 装饰器是如何工作的?它们在实际项目中有哪些常见用途?
  5. 在数据分析管道的基础上,还可以添加哪些数据处理功能来增强其实用性?

更多推荐