数据分析笔记12:函数
数据分析笔记12:函数
函数的概念与作用
为什么需要函数
问题场景:如果某段代码需要多次使用,每次都重写会导致:
- 代码冗余。
- 维护困难。
- 效率低下。
解决方案:将具有独立功能的代码封装成函数,需要时直接调用。
函数的优势:
- 提高代码重用性:写一次,多处调用。
- 提高开发效率:避免重复编写。
- 便于维护:修改函数定义即可,不需要到处修改。
函数的定义与调用
基本语法:
def 函数名(参数1, 参数2, ...):"""函数功能说明"""函数体代码return 返回值
关键字说明:
- def:定义函数的关键字(define的缩写)。
- 函数名:遵循变量命名规则。
- 参数:可选,可以有多个或无参数。
- 冒号:函数定义行末尾必须有冒号。
- 缩进:函数体代码必须缩进4个空格。
- return:返回结果(可选)。
简单示例:
# 定义函数
def print_info():for i in range(6):print("hello")# 调用函数
print_info() # 输出6次"hello"
print_info() # 再次调用,再输出6次
重要:
- 定义函数时,代码不会执行。
- 只有调用函数时,函数体代码才会执行。
- 调用方式:函数名()。
实际应用示例:ATM界面。
# 定义选择功能界面
def select_func():print("=" * 25)print("请选择功能:")print("1. 查询余额")print("2. 取款")print("3. 存款")print("=" * 25)# 使用场景
print("密码正确,登录成功")
select_func() # 显示功能菜单print("余额查询完毕")
select_func() # 再次显示功能菜单print("取了3000元")
select_func() # 再次显示功能菜单
这样可以大大减少代码量,提高可维护性。
函数的参数
为什么需要参数
没有参数的函数功能固定,灵活性差:
def add_num():result = 2 + 3print(result)
这个函数只能计算2+3,无法计算其他数字。
带参数的函数:
def add_num(a, b):result = a + bprint(result)add_num(2, 3) # 5
add_num(4, 5) # 9
add_num(15, 25) # 40
参数说明:
- 形参(形式参数):定义函数时的参数 a, b,只是一个形式,还没有具体值。
- 实参(实际参数):调用函数时传入的具体值 2, 3。
参数传递方式
- 位置传参(最常用): 按照参数位置顺序传递,顺序不能错。
def calculate(a, b, c):print(f"A={a}, B={b}, C={c}")calculate(3, 2, 4)
# 输出:A=3, B=2, C=4
# 3传给a,2传给b,4传给c
注意事项:
- 实参数量必须与形参数量一致。
- 顺序必须对应,否则结果错误。
def subtract(a, b):print(a - b)subtract(3, 2) # 1(3-2)
subtract(2, 3) # -1(2-3) # 顺序不同,结果不同
- 关键字传参(更灵活): 使用 参数名=值 的方式传递,顺序可以任意。
def calculate(a, b, c):print(f"A={a}")print(f"B={b}")print(f"C={c}")print("-" * 25)# 顺序可以任意
calculate(a=3, c=2, b=4)
# 输出:A=3, B=4, C=2calculate(c=5, a=4, b=6)
# 输出:A=4, B=6, C=5
优势:
- 不需要记住参数顺序。
- 代码可读性更强。
- 适合参数较多的函数。
位置传参 vs 关键字传参:
| 传参方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 位置传参 | 简洁 | 必须记住顺序 | 参数少且顺序明确 |
| 关键字传参 | 灵活,可读性强 | 稍显冗长 | 参数多或顺序不明确 |
返回值(return)
为什么需要返回值
函数执行后的结果需要返回给调用者,否则结果只存在于函数内部。
没有返回值的情况:
def sum_num(a, b):result = a + b# 没有returnret = sum_num(2, 3)
print(ret) # None(什么都没有)
虽然函数内部计算了 2+3=5,但没有返回,外部无法获取结果。
使用return返回值:
def sum_num(a, b):result = a + breturn result # 返回结果ret = sum_num(2, 3)
print(ret) # 5
工作流程:
- 调用 sum_num(2, 3)。
- 函数内部计算 2+3=5。
- return 5 将结果返回。
- ret 接收到返回值 5。
- 打印 ret 得到 5。
返回多个值:
def func():return 2, 3, 4, 5value = func()
print(value) # (2, 3, 4, 5)
print(type(value)) # <class 'tuple'>
重点:当返回多个值时,Python会自动将它们封装成元组返回。
return的特殊作用:立即终止函数。
def func():print("2")return "结束"print("3") # 这行代码永远不会执行ret = func()
print(ret)
# 输出:
# 2
# 结束
重要特性:一旦执行到 return,函数立即终止,后面的代码不再执行。
最佳实践:
- return 通常放在函数最后一行。
- 如果中途return,确保这是有意的逻辑(如提前退出)。
函数的嵌套调用
概念:在一个函数内部调用另一个函数。
示例:
def test_b():print("--- test_b start ---")print("test_b函数执行的代码...")print("--- test_b end ---")def test_a():print("--- test_a start ---")test_b() # 调用test_b函数print("--- test_a end ---")# 调用test_a
test_a()
输出结果: --- test_a start ---
--- test_b start ---
test_b函数执行的代码...
--- test_b end ---
--- test_a end ---
执行流程分析:
- 调用 test_a()。
- 执行 test_a 第一行:打印 "test_a start"。
- 遇到 test_b(),跳转到 test_b 函数。
- 执行 test_b 的所有代码。
- test_b 执行完毕,返回 test_a。
- 继续执行 test_a 剩余代码:打印 "test_a end"。
关键理解:函数调用会暂停当前函数的执行,转到被调用函数,执行完毕后再返回继续。
函数重点:
- 定义与调用:def 定义,函数名() 调用。
- 参数传递:位置传参(按顺序)、关键字传参(指定名称)。
- 返回值:return 返回结果给调用者,遇到return立即终止函数。
- 函数嵌套:函数内可以调用其他函数。
- 阅读技巧:先看调用处,理解程序流程,再看函数定义。
如何阅读代码
阅读顺序
错误方式:从头到尾按顺序读,遇到函数定义就陷入细节。
正确方式:
- 跳过函数定义,直接找到函数调用的地方。
- 从调用处开始,按调用顺序理解程序逻辑。
- 需要时再回到函数定义查看具体实现。
实际案例:爬虫代码
# 大量函数定义(先跳过)
def crawl_data():# 爬取数据的120行代码...def parse_data():# 解析数据的90行代码...def save_data():# 保存数据的60行代码...# === 从这里开始看!===
crawl_data() # 第一步:爬取数据
parse_data() # 第二步:解析数据
save_data() # 第三步:保存数据
阅读步骤:
- 直接跳到底部,看到三个函数调用。
- 理解程序逻辑:爬取 → 解析 → 保存。
- 需要了解细节时,再回到对应函数定义。
阅读复杂代码的技巧
- 先看调用链:理解程序的主流程。
- 再看实现:深入每个函数的具体逻辑。
- 关注数据流:数据如何从一个函数传递到另一个。
- 注意返回值:函数之间如何交换信息。
核心思想:先见森林,再看树木。先理解整体逻辑,再深入细节。
延伸思考
函数的局限性
- 只能控制第一类错误,第二类错误难以量化。
- 样本大小对检验效力的影响。
- 实际意义与统计意义的区别。
实际应用考虑
- 如何在实务中平衡两类错误的成本。
- 多重比较问题及其解决方案。
- 非参数检验方法的选择时机。
