Chapter 06

函 数

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

欢迎关注微信公众号

coder程 查令十街84号

本章目录

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 # 有函数:一次定义,处处调用 deftriangle_area(base): return0.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返回值

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

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

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

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

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

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

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

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

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

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

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

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

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

count=0 defincrement(): globalcount count+=1 increment() print(count) # 1

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

2. 函数式编程实例

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

# 高阶函数:接收函数作为参数 defapply_twice(f,x): return f(f(x)) defadd_ten(x): returnx+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 deffactorial(n): ifn<=1: return1 returnn* factorial(n-1) print(factorial(5)) # 120
# 斐波那契数列 deffib(n): ifn<=1: returnn return fib(n-1)+ fib(n-2) foriinrange(10): print(fib(i),end=" ") # 0 1 1 2 3 5 8 13 21 34

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

3. 匿名函数 lambda

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

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

lambda 的典型使用场景

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

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

4. 面向过程 vs 面向对象

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

# 面向过程:模拟体育比赛 defget_inputs(): prob_a= float(input("选手A胜率: ")) prob_b= float(input("选手B胜率: ")) n= int(input("比赛场次: ")) returnprob_a,prob_b,n defsim_one_game(prob_a,prob_b): # 模拟一场比赛 importrandomscore_a, score_b=0,0 whilenotgame_over(score_a,score_b): ifrandom. random()<prob_a: score_a+=1 else: score_b+=1 returnscore_a,score_b

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

模块化设计思想

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

# main.py — 主程序框架 defmain(): 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) defget_inputs(): # 获取用户输入 pass defsim_n_games(prob_a,prob_b,n): # 模拟n场比赛 pass defprint_summary(wins_a,wins_b): # 输出结果 pass if__name__=="__main__": main()

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

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

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

本章总结

下一章 ▶