Chapter 06

函 数

Python基础 · 模块化编程与代码复用

欢迎关注微信公众号

coder程

本章目录

1. 为什么需要函数

函数是将一段可复用代码 封装 起来的基本单元。使用函数的目的:

# 没有函数:重复写三次同样的逻辑 a, b, c = 3, 4, 5 area_a = 0.5 * a * a area_b = 0.5 * b * b area_c = 0.5 * c * c # 有函数:一次定义,处处调用 def triangle_area(base): return 0.5 * base * base area_a = triangle_area(3) area_b = triangle_area(4) area_c = triangle_area(5)

1. 函数的定义与调用

函数通过 def 关键字定义,语法结构清晰:

def 函数名(参数1, 参数2, ...): """文档字符串(docstring)说明函数作用""" # 函数体 return 返回值

调用函数 :写出函数名并传入参数。

# 定义:计算两数之和 def add(a, b): return a + b # 调用 result = add(3, 5) print(result) # 8 # 无参数、无返回值 def say_hello(): print("Hello, Python!") say_hello()

1. 参数传递 — 位置与关键字

Python 支持多种传参方式,灵活组合使用。

# 位置参数:按顺序传递 def greet(name, greeting): print(f"{greeting}, {name}!") greet("Alice", "Good morning") # 关键字参数:指定参数名,顺序无关 greet(greeting="Hi", name="Bob") # 默认值参数 def power(base, exp=2): return base ** exp print(power(3)) # 9 (3²) print(power(2, 3)) # 8 (2³)

注意 :默认参数如果使用可变对象(如列表),可能存在副作用。

1. 可变参数 *args 与 **kwargs

当参数数量不确定时,使用可变参数收集所有传入值。

# *args 收集多余的位置参数,变为元组 def total(*args): result = 0 for num in args: result += num return result print(total(1, 2, 3)) # 6 print(total(10, 20)) # 30
# **kwargs 收集多余的关键字参数,变为字典 def profile(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}") profile(name="Alice", age=25, city="Beijing")

1. 作用域 — 局部变量与全局变量

变量在哪里定义,决定了它能被谁访问。

x = 10 # 全局变量 def demo(): y = 5 # 局部变量,只能在函数内访问 print(y) # 5 print(x) # 10 (可以读取全局变量) demo() # print(y) # 错误!y 在函数外部不存在

global 关键字 :在函数内部修改全局变量。

count = 0 def increment(): global count count += 1 increment() print(count) # 1

LEGB 规则 :查找顺序为 L ocal → E nclosing → G lobal → B uilt-in。

2. 函数式编程实例

Python 支持一等函数(函数可以作为参数、返回值)。

# 高阶函数:接收函数作为参数 def apply_twice(f, x): return f(f(x)) def add_ten(x): return x + 10 print(apply_twice(add_ten, 5)) # 25

map / filter / reduce :经典函数式工具。

nums = [1, 2, 3, 4, 5] # map: 对每个元素应用函数 squares = list(map(lambda x: x**2, nums)) # [1, 4, 9, 16, 25] # filter: 保留满足条件的元素 evens = list(filter(lambda x: x % 2 == 0, nums)) # [2, 4]

2. 递归函数

函数 调用自身 来解决子问题。必须有 终止条件 ,否则无限递归。

# 阶乘: n! = n × (n-1) × ... × 1 def factorial(n): if n <= 1: return 1 return n * factorial(n - 1) print(factorial(5)) # 120
# 斐波那契数列 def fib(n): if n <= 1: return n return fib(n - 1) + fib(n - 2) for i in range(10): print(fib(i), end=" ") # 0 1 1 2 3 5 8 13 21 34

注意 :递归虽然优雅,但深度过大时会栈溢出。Python 默认递归深度限制为1000。

3. 匿名函数 lambda

lambda 用于创建 小型、一次性 的匿名函数,语法紧凑。

# 普通函数 def square(x): return x ** 2 # 等价的 lambda square = lambda x: x ** 2 print(square(5)) # 25

lambda 的典型使用场景 :

# 作为排序的 key students = [("Alice", 85), ("Bob", 92), ("Carol", 78)] students.sort(key=lambda x: x[1]) # 按成绩排序 # 配合 map 使用 nums = [1, 2, 3, 4] doubled = list(map(lambda x: x * 2, nums)) # [2, 4, 6, 8]

限制 :lambda 只能写单行表达式,不能包含语句(如赋值、循环)。

4. 面向过程 vs 面向对象

函数是实现 面向过程编程 的核心工具。它将程序分解为按步骤执行的函数调用链。

# 面向过程:模拟体育比赛 def get_inputs(): prob_a = float(input("选手A胜率: ")) prob_b = float(input("选手B胜率: ")) n = int(input("比赛场次: ")) return prob_a, prob_b, n def sim_one_game(prob_a, prob_b): # 模拟一场比赛 import random score_a, score_b = 0, 0 while not game_over(score_a, score_b): if random.random() < prob_a: score_a += 1 else: score_b += 1 return score_a, score_b

面向过程适合 流程清晰、步骤明确 的任务。当数据与操作变得复杂时,面向对象更合适。

模块化设计思想

将大型程序拆分为 主程序 + 多个功能函数 ,每个函数职责单一。

# main.py — 主程序框架 def main(): prob_a, prob_b, n = get_inputs() wins_a, wins_b = sim_n_games(prob_a, prob_b, n) print_summary(wins_a, wins_b) def get_inputs(): # 获取用户输入 pass def sim_n_games(prob_a, prob_b, n): # 模拟n场比赛 pass def print_summary(wins_a, wins_b): # 输出结果 pass if __name__ == "__main__": main()

if __name__ == "__main__" :确保模块被直接运行时才执行主程序,被导入时不执行。

综合练习:模块化温度转换器

# 温度转换模块 def c_to_f(c): """摄氏度转华氏度""" return c * 9 / 5 + 32 def f_to_c(f): """华氏度转摄氏度""" return (f - 32) * 5 / 9 def batch_convert(temps, direction="c2f"): """批量转换""" func = c_to_f if direction == "c2f" else f_to_c return [func(t) for t in temps] # 使用 celsius = [0, 10, 20, 30, 40] fahrenheit = batch_convert(celsius) print(fahrenheit) # [32.0, 50.0, 68.0, 86.0, 104.0]

本章总结

下一章 ▶