Skip to content

Module 5: 函数与模块

让代码可复用 —— 从重复劳动到优雅编程


本章概览

写代码时,你会发现很多操作需要重复执行:计算统计量、清洗数据、运行回归。函数让你把这些操作封装起来,随时调用,避免重复代码。模块则让你组织和重用别人(或自己)写好的函数。掌握函数和模块,你的代码将从"脚本"升级为"程序"。


学习目标

学完本章后,你将能够:

  • 理解函数的概念和作用
  • 定义和调用自己的函数
  • 掌握参数传递(位置参数、关键字参数、默认参数)
  • 使用 *args**kwargs 处理可变参数
  • 理解 Lambda 函数和应用场景
  • 导入和使用标准库与第三方模块
  • 组织自己的代码为模块和包
  • 对比 Stata 的 program 和 R 的 function()

章节内容

01 - 函数基础

核心问题: 如何让代码可复用?

核心内容:

  • 函数的定义与调用
  • 参数(parameters)和返回值(return)
  • 文档字符串(docstring)
  • 局部变量 vs 全局变量
  • None 的含义
  • 对比 Stata(program define)和 R(function())

实际应用:

python
def calculate_bmi(weight, height):
    """计算 BMI 指数
    
    参数:
        weight: 体重(千克)
        height: 身高(米)
    
    返回:
        BMI 值
    """
    bmi = weight / (height ** 2)
    return bmi

# 调用函数
result = calculate_bmi(70, 1.75)
print(f"BMI: {result:.2f}")  # BMI: 22.86

研究场景:

  • 计算统计量(均值、标准差、分位数)
  • 数据清洗(缺失值处理、异常值检测)
  • 重复分析(多个模型、多个子样本)
  • 稳健性检验

02 - 函数参数

核心问题: 如何灵活地向函数传递数据?

核心内容:

  • 位置参数(positional arguments):按顺序传递
  • 关键字参数(keyword arguments):按名称传递
  • 默认参数(default arguments):提供默认值
  • 可变位置参数(*args):接受任意数量的位置参数
  • 可变关键字参数(**kwargs):接受任意数量的关键字参数
  • 参数顺序规则
  • 参数解包(*, **)

实际应用:

python
def run_regression(y, X, model_type="OLS", robust=True, **options):
    """运行回归分析
    
    参数:
        y: 因变量
        X: 自变量
        model_type: 模型类型(默认 OLS)
        robust: 是否使用稳健标准误(默认 True)
        **options: 其他选项
    """
    print(f"模型: {model_type}")
    print(f"稳健标准误: {robust}")
    print(f"其他选项: {options}")

# 灵活调用
run_regression(y, X)  # 使用默认参数
run_regression(y, X, model_type="Logit")  # 修改模型类型
run_regression(y, X, robust=False, cluster="firm_id")  # 传递额外选项

研究场景:

  • 提供默认配置(显著性水平、迭代次数)
  • 灵活的模型选项
  • 批量处理(传递多个参数组合)

03 - Lambda 函数

核心问题: 什么时候用匿名函数?

核心内容:

  • Lambda 语法:lambda arguments: expression
  • 与普通函数的对比
  • 使用场景:
    • 排序(sorted(), list.sort())
    • 映射(map())
    • 过滤(filter())
    • Pandas 数据操作
  • Lambda 的局限性

实际应用:

python
# 按收入排序学生列表
students = [
    {"name": "Alice", "income": 50000},
    {"name": "Bob", "income": 75000},
    {"name": "Carol", "income": 60000}
]

sorted_students = sorted(students, key=lambda x: x["income"])

# Pandas 数据清洗
df["log_income"] = df["income"].apply(lambda x: np.log(x) if x > 0 else None)

# 过滤高收入者
high_earners = list(filter(lambda x: x["income"] > 60000, students))

何时使用 Lambda?

  • 简单的一次性函数
  • 排序、映射、过滤
  • Pandas apply() 操作
  • 复杂逻辑(用普通函数)
  • 需要文档字符串(用普通函数)

04 - 模块与包

核心问题: 如何组织和重用代码?

核心内容:

  • 模块(Module):单个 .py 文件
  • (Package):包含多个模块的文件夹
  • 导入方式:
    • import module
    • from module import function
    • import module as alias
    • from module import *(不推荐)
  • 标准库介绍:
    • math:数学函数
    • statistics:统计函数
    • random:随机数生成
    • datetime:日期时间处理
    • ossys:系统操作
  • 第三方库安装(pip install)
  • 创建自己的模块和包

实际应用:

python
# 导入标准库
import math
import statistics as stats
from datetime import datetime

# 使用数学函数
log_income = math.log(50000)
sqrt_value = math.sqrt(100)

# 计算统计量
mean_income = stats.mean([50000, 60000, 75000])
median_income = stats.median([50000, 60000, 75000])

# 导入数据分析库
import numpy as np
import pandas as pd
import statsmodels.api as sm

# 创建自己的模块
# my_stats.py
def winsorize(data, lower=0.01, upper=0.99):
    """缩尾处理"""
    p_lower = np.quantile(data, lower)
    p_upper = np.quantile(data, upper)
    return np.clip(data, p_lower, p_upper)

# 在其他文件中导入
from my_stats import winsorize
clean_data = winsorize(incomes)

研究场景:

  • 使用 NumPy 进行数值计算
  • 使用 Pandas 处理数据
  • 使用 statsmodels 运行回归
  • 组织自己的数据清洗函数库

05 - 小结和复习

内容:

  • 函数设计最佳实践
  • 常见错误和调试技巧
  • 模块组织建议
  • 综合练习题
  • Stata/R/Python 对比

Stata vs R vs Python 函数对比

定义函数

语言语法
Stataprogram define func_name
Rfunc_name <- function(args) { ... }
Pythondef func_name(args): ...

示例:计算 BMI

Stata:

stata
program define calc_bmi
    args weight height
    gen bmi = `weight' / (`height'^2)
end

calc_bmi 70 1.75

R:

r
calc_bmi <- function(weight, height) {
  bmi <- weight / (height^2)
  return(bmi)
}

result <- calc_bmi(70, 1.75)

Python:

python
def calc_bmi(weight, height):
    bmi = weight / (height ** 2)
    return bmi

result = calc_bmi(70, 1.75)

如何学习本章?

学习路线

第 1 天(3小时): 函数基础

  • 阅读 01 - 函数基础
  • 定义简单函数
  • 理解返回值和文档字符串

第 2 天(3小时): 函数参数

  • 阅读 02 - 函数参数
  • 练习位置/关键字/默认参数
  • 理解 *args**kwargs

第 3 天(2小时): Lambda 函数

  • 阅读 03 - Lambda 函数
  • 用 Lambda 排序和过滤
  • 在 Pandas 中使用 Lambda

第 4 天(3小时): 模块与包

  • 阅读 04 - 模块与包
  • 导入和使用标准库
  • 创建自己的模块

第 5 天(2小时): 复习和综合应用

  • 完成 05 - 小结和复习
  • 编写完整的分析函数库
  • 组织代码为模块

总时间: 13 小时(1-2 周)

最小化学习路径

如果时间有限:

必学(核心概念,8小时):

  • 01 - 函数基础(完整学习)
  • 02 - 函数参数(位置/关键字/默认)
  • 04 - 模块与包(导入标准库)

选学(进阶技巧):

  • *args**kwargs
  • Lambda 函数
  • 创建自己的包

学习建议

  1. 从需求出发

    • 发现重复代码 → 提取为函数
    • 需要配置选项 → 使用默认参数
    • 代码越来越长 → 拆分为模块
  2. 函数设计原则

    • 单一职责:一个函数只做一件事
    • 有意义的名称:calculate_bmi()func1()
    • 写文档字符串:说明功能、参数、返回值
    • 避免副作用:尽量不修改全局变量
  3. 实践项目 创建一个 my_stats.py 模块,包含:

    python
    # my_stats.py
    
    def mean(data):
        """计算均值"""
        return sum(data) / len(data)
    
    def std(data):
        """计算标准差"""
        m = mean(data)
        variance = sum((x - m) ** 2 for x in data) / len(data)
        return variance ** 0.5
    
    def winsorize(data, lower=0.01, upper=0.99):
        """缩尾处理"""
        import numpy as np
        p_lower = np.quantile(data, lower)
        p_upper = np.quantile(data, upper)
        return np.clip(data, p_lower, p_upper)
  4. 对比学习

    • 用 Python 复现 Stata 的 program
    • 用 Python 复现 R 的 function()
    • 理解语法差异背后的哲学

常见问题

Q: 函数和变量有什么区别? A: 变量存储数据,函数存储操作。变量是"名词",函数是"动词"。

Q: 什么时候应该写函数? A: 遵循 DRY 原则(Don't Repeat Yourself)。如果一段代码用了 3 次以上,就应该提取为函数。

Q: 为什么需要文档字符串? A: 几周后你会忘记函数的用法。文档字符串是写给未来的自己(和合作者)的说明书。

Q: returnprint() 有什么区别? A:

  • return:将值返回给调用者,可以赋值给变量
  • print():仅在屏幕上显示,不返回值
python
def bad_function(x):
    print(x * 2)  # 只打印,不返回

def good_function(x):
    return x * 2  # 返回值

result = bad_function(5)  # result = None
result = good_function(5)  # result = 10

Q: 什么时候用 Lambda,什么时候用普通函数? A:

  • Lambda:简单的一行表达式(排序、映射、过滤)
  • 普通函数:复杂逻辑、多行代码、需要文档字符串

Q: 如何找到有用的第三方库? A:

  • 数据分析:numpy, pandas, statsmodels
  • 数据可视化:matplotlib, seaborn, plotly
  • 机器学习:scikit-learn, xgboost, lightgbm
  • 文本分析:nltk, spaCy, transformers
  • 网络爬虫:requests, beautifulsoup4, scrapy

下一步

完成本章后,你将掌握:

  • 编写可复用的函数
  • 灵活使用参数传递
  • 导入和组织模块
  • 代码从"脚本"升级为"程序"

Module 6-7 中,我们将学习 Pandas,这是 Python 数据分析的核心库,整合了我们学过的所有概念!

Module 8-9 中,我们将学习数据可视化和高级数据处理技巧。

恭喜!完成前 5 个模块,你已经掌握了 Python 的核心语法!接下来就是数据分析的实战了!


快速链接

基于 MIT 许可证发布。内容版权归作者所有。