🐍 PYTHON 零基础入门系列 · 图解版
深入理解 Python 函数
配图说明 · 逐行代码解析 · 从零开始彻底搞懂函数每一个细节
📚 10 大知识点🖼 4 张配图💻 15+ 代码示例🧩 4 道自测题
[① 什么是函数](#① 什么是函数)[② 函数结构](#② 函数结构)[③ 执行流程](#③ 执行流程)[④ 参数类型](#④ 参数类型)[⑤ return用法](#⑤ return用法)[⑥ 作用域](#⑥ 作用域)[⑦ 综合实战](#⑦ 综合实战)[⑧ 为什么用函数](#⑧ 为什么用函数)[⑨ Lambda](#⑨ Lambda)[⑩ 常见错误](#⑩ 常见错误)
1
什么是函数?--- 用一个生活比喻彻底理解
🍳 生活比喻 · 咖啡机模型
想象一台全自动咖啡机 :
你只需要 投入咖啡豆 + 水(输入/参数) ,按下按钮(调用),
机器内部自动研磨、加热、萃取(函数体运行),
最终出来一杯咖啡(输出/返回值)。
你完全不需要知道 机器内部怎么工作------只要会"使用"它。
函数就是这台咖啡机! 封装好的、可重复使用的一段代码。

📌**图解说明:**左边的咖啡豆和水 = 函数的输入参数; 中间机器内部齿轮 = 函数体执行逻辑; 右边咖啡杯 = 函数的返回值(return)
📌 人话版定义
函数是一段被命名的代码块,专门完成某项具体任务。定义一次,随时随地调用,避免重复写相同的代码。就像你存了一个手机联系人,以后直接点名字打电话,不需要每次都重新输电话号码。
2
函数的结构解剖--- 逐行、逐部分读懂每个组成
📌**图解说明:**图中用不同颜色高亮了函数的每一个组成部分,箭头标注了每部分的名称和作用
🔬 逐部分解析对照表
| 部分 | 代码示例 | 作用说明 | 类比 |
|---|---|---|---|
| def 关键字 | def | 告诉 Python "我要开始定义一个函数了",就像写信开头要写"亲爱的..." | 📢 宣告词 |
| 函数名 | greet | 函数的名字,自己取,见名知意。之后调用时就用这个名字。命名规则:小写+下划线 | 🏷 名字 |
| 参数列表 | (name, times=1) | 括号内写参数,相当于函数的"输入接口"。可以有多个,可以有默认值 | 📥 输入接口 |
| 冒号 : | : | 固定语法,必须写,告诉 Python 函数体要开始了 | 🚪 开始标记 |
| 函数体 | (缩进4格) | 真正干活的代码,必须缩进4个空格(或1个Tab),Python 靠缩进判断属于哪个函数 | ⚙️ 内部机器 |
| return | return message | 把结果"返回"给调用者。函数执行到这里就停止,把值交出去。没有return则返回 None | 📤 输出接口 |
function_anatomy.py --- 完整注释版
# ↓ 关键字 ↓ 函数名 ↓ 参数1 ↓ 参数2(有默认值)
def greet (name, times=1):
# ↑ 冒号不能少!
# ↓ 函数体:缩进4格,这里才是真正干活的代码
message = f"你好,{name}!" * times
return message
# ↑ return 把结果送出去,函数在这里结束
# ── 调用函数 ──
result = greet("小明", 2)
# result = "你好,小明!你好,小明!"
print(result)
3
函数是怎么运行的?--- 四步执行流程图解
📌**图解说明:**函数执行是一个"去而复返"的过程 ------ 调用时跳进去,执行完再跳回来,把结果带回
1
📝 定义
用 def 写好函数。此时代码不运行,只是把函数"存"进内存
2
📞 调用
写函数名加括号,传入实际参数,Python 就会"去执行"这个函数
3
⚙️ 执行
Python 跳进函数体,把参数赋值,逐行运行函数内的代码
4
🔙 返回
遇到 return(或到函数末尾),带着结果跳回调用处,继续往下执行
execution_flow.py --- 追踪执行顺序
# ── 步骤 1:定义(只是"登记",不执行)──
def add(a, b):
print(f"正在计算:{a} + {b}") # 步骤3:跳进来执行第1行
result = a + b # 步骤3:执行第2行
return result # 步骤4:return,带着结果回去
print("调用之前") # 先执行这行
x = add(3, 5) # 步骤2:调用,跳进 add 函数
print(f"结果是:{x}") # 步骤4结束后,继续在这里
print("调用之后")
# 输出顺序:
# 调用之前
# 正在计算:3 + 5
# 结果是:8
# 调用之后
💡 关键理解: 定义函数时代码不执行,必须"调用"它才会运行。 就像咖啡机插好电不会出咖啡,按下按钮才会运行。
4
参数的五种写法--- 从最简单到最灵活
① 无参数
函数不需要任何输入,直接执行固定任务
def say_hello():
② 必填参数(位置参数)
调用时必须按顺序传,缺一不可
def add(a, b):
③ 默认参数
有默认值,调用时可省略,也可传新值覆盖
def greet(name, times=1):
④ *args(可变位置)
接收任意数量参数,打包成元组
def sum_all(*numbers):
⑤ **kwargs(可变关键字)
接收任意"名=值"参数,打包成字典
def profile(**info):
param_types.py --- 五种参数完整演示
# ① 无参数 —— 最简单
def say_hello():
print("你好!")
say_hello() # 调用时括号里什么都不写
# 输出:你好!
# ─────────────────────────────────────────
# ② 必填参数 —— 顺序不能乱
def add(a, b):
return a + b
print(add(3, 5)) # ✅ 输出:8
# add(3) # ❌ 报错:缺少参数 b
# ─────────────────────────────────────────
# ③ 默认参数 —— 可传可不传
def make_coffee(size="中杯", sugar=1):
print(f"制作:{size},加糖 {sugar} 块")
make_coffee() # 中杯,加糖 1 块
make_coffee("大杯") # 大杯,加糖 1 块
make_coffee("大杯", 3) # 大杯,加糖 3 块
make_coffee(sugar=0) # 关键字传参,中杯,无糖
# ─────────────────────────────────────────
# ④ *args —— 传多少个都行
def sum_all(*numbers):
# numbers 是一个元组,如 (1, 2, 3)
return sum(numbers)
print(sum_all(1, 2, 3)) # 6
print(sum_all(10, 20, 30, 40)) # 100
# ─────────────────────────────────────────
# ⑤ **kwargs —— 传任意"名=值"
def create_profile(**info):
# info 是一个字典,如 {'name':'黎俊杰', 'age':20}
for k, v in info.items():
print(f" {k}: {v}")
create_profile(name="黎俊杰", age=20, major="数据科学")
# 输出:
# name: 黎俊杰
# age: 20
# major: 数据科学
5
return 的各种用法--- 函数的"出口"
return_usage.py --- 四种 return 情况
# ── 情况 1:返回单个值(最常见)──
def square(x):
return x ** 2 # x 的平方
r = square(5)
print(r) # 输出:25
# ── 情况 2:返回多个值(Python 会打包成元组)──
def min_max(lst):
return min(lst), max(lst) # 同时返回最小值和最大值
lo, hi = min_max([3, 1, 9, 4])
print(f"最小:{lo},最大:{hi}") # 最小:1,最大:9
# ── 情况 3:没有 return(返回 None)──
def show_info(msg):
print(msg) # 只打印,没有 return
result = show_info("Hi")
print(result) # 输出:None(空值)
# ── 情况 4:提前退出(条件检查)──
def divide(a, b):
if b == 0:
print("错误:除数不能为0!")
return # 提前结束,避免程序崩溃
return a / b
print(divide(10, 2)) # 5.0
print(divide(10, 0)) # 错误:除数不能为0!
📋 return 使用要点总结
| 情况 | 语法 | 调用方得到什么 |
|---|---|---|
| ✅ 返回单值 | return x | 变量 x 的值 |
| ✅ 返回多值 | return a, b | 元组 (a, b),可以解包 |
| ⚪ 无 return | 函数末尾没有return | None(空值) |
| 🔴 提前退出 | return(不带值) | None,函数立即结束 |
6
变量的"生命范围"--- 局部变量 vs 全局变量
📌**图解说明:**全局变量像客厅的电视,整个家(整个程序)都能看到; 局部变量像卧室里的私人物品,只有函数内部能使用,外面无法访问
🏠 房间比喻
全局变量 = 客厅里的电视:全家人(整个程序)都能看。
局部变量 = 你卧室里的私人日记:只有你自己(函数内部)才能翻,出了房间就没了。
函数结束,局部变量就自动消失,就像你关上卧室门,外面的人根本不知道里面有什么。
scope.py --- 作用域完整演示
score = 100 # 全局变量:整个文件的函数都能访问它
def show_score():
print(score) # ✅ 函数内可以"读"全局变量
def calculate():
bonus = 20 # 局部变量:只在 calculate 函数内存在
print(score + bonus) # ✅ 可以同时用全局+局部变量
# 函数结束,bonus 就消失了
def modify_score():
global score # ⚠️ 要修改全局变量,必须先声明 global
score += 10
show_score() # 100
calculate() # 120
modify_score()
show_score() # 110(被修改了)
# ❌ 以下会报错:局部变量在函数外不存在
# print(bonus) → NameError: name 'bonus' is not defined
7
综合实战--- 用函数开发"学生成绩管理系统"
💡 **目标:**把成绩管理系统拆解成多个小函数,每个函数只负责一件事, 代码清晰、可复用、方便修改。这就是"函数式编程思维"。
🗂 函数拆解设计
| 函数名 | 输入 | 输出 | 职责 |
|---|---|---|---|
| get_average(scores) | 成绩列表 | 浮点数平均分 | 计算平均分 |
| get_grade(avg) | 平均分数值 | 等级字符串 | 评定等级 |
| print_report(student) | 学生字典 | 无(只打印) | 打印单人报告 |
| print_class_report(list) | 学生列表 | 无 | 打印全班报告 |
student_manager.py --- 完整注释版
# =====================================================
# 学生成绩管理系统 — 数据2501班
# =====================================================
# 数据:学生列表,每个学生是一个字典
students = [
{"name": "黎俊杰", "scores": [90, 85, 92]},
{"name": "李天宇", "scores": [78, 88, 76]},
{"name": "刘文财", "scores": [95, 92, 98]},
{"name": "陈扬", "scores": [72, 68, 80]},
{"name": "徐嘉豪", "scores": [88, 91, 87]},
]
# ── 函数① :计算平均分 ──────────────────────────────
def get_average(scores):
# 接收分数列表,返回浮点数平均分
return sum(scores) / len(scores)
# ── 函数② :评定等级 ──────────────────────────────
def get_grade(avg):
# 根据平均分返回等级字符串
if avg >= 90: return "优秀 🏆"
elif avg >= 80: return "良好 👍"
elif avg >= 60: return "及格 📝"
else: return "不及格 ❌"
# ── 函数③ :打印单个学生报告 ─────────────────────
def print_report(student):
# 调用前两个函数,打印一名学生的完整报告
avg = get_average(student["scores"]) # 调用函数①
grade = get_grade(avg) # 调用函数②
print(f" {student['name']:5s} | 平均:{avg:5.1f} | {grade}")
# ── 函数④ :打印全班报告 ────────────────────────
def print_class_report(students_list):
# 遍历学生列表,为每人调用函数③
print("=" * 38)
print(" 📊 数据2501班成绩报告单")
print("=" * 38)
for stu in students_list:
print_report(stu) # 调用函数③
print("=" * 38)
# ── 主程序入口 ─────────────────────────────────
print_class_report(students)
# ======================================
# 📊 数据2501班成绩报告单
# ======================================
# 黎俊杰 | 平均: 89.0 | 良好 👍
# 李天宇 | 平均: 80.7 | 良好 👍
# 刘文财 | 平均: 95.0 | 优秀 🏆
# 陈扬 | 平均: 73.3 | 及格 📝
# 徐嘉豪 | 平均: 88.7 | 良好 👍
# ======================================
8
为什么要用函数?--- 有/无函数代码对比
❌ 不用函数(重复代码 × 3)
# 计算甲的成绩
sa = [80, 90, 70]
ta = 0
for s in sa: ta += s
avg_a = ta / len(sa)
# 计算乙的成绩(复制粘贴😩)
sb = [60, 85, 95]
tb = 0
for s in sb: tb += s
avg_b = tb / len(sb)
# 计算丙的成绩(又复制粘贴😩)
sc = [99, 70, 88]
tc = 0
for s in sc: tc += s
avg_c = tc / len(sc)
✅ 用函数(一次定义,三次复用)
# 只写一次!
def average(scores):
return sum(scores) / len(scores)
# 复用三次,代码简洁优雅 ✨
avg_a = average([80, 90, 70])
avg_b = average([60, 85, 95])
avg_c = average([99, 70, 88])
# 需要改计算逻辑?
# 只改 average 函数内部一处 ✅
# 不需要找3处分别改 ❌
📋 函数的四大核心好处
| 好处 | 说明 | 实际效果 |
|---|---|---|
| ♻️ 代码复用 | 写一次,到处用 | 代码量减少 60%+ |
| 🎯 职责单一 | 每个函数只做一件事 | 逻辑清晰,好理解 |
| 🛠 易于维护 | 改 bug 只改函数内部 | 一处修改,全局生效 |
| 📖 可读性强 | 函数名就是注释 | 代码读起来像自然语言 |
9
Lambda 匿名函数--- 简单任务的"一行函数"
💡 当函数逻辑只有一行 时,可以用 lambda 简写,省去 def 和函数名。 常用于排序的 key 参数、map/filter 等场合。
lambda_demo.py
# ── 普通 def 写法 vs Lambda 写法 对比 ──
def double_def(x):
return x * 2
double_lambda = lambda x: x * 2
# ↑参数 ↑冒号 ↑ 返回值(不需要 return 关键字)
print(double_def(5)) # 10
print(double_lambda(5)) # 10 —— 结果完全一样
# ── 实战:对学生按平均分排序 ──
students = [
("黎俊杰", 89), ("刘文财", 95),
("李天宇", 80), ("陈扬", 73)
]
# 按第2个元素(分数)降序排
students.sort(key=lambda stu: stu[1], reverse=True)
print(students)
# [('刘文财', 95), ('黎俊杰', 89), ('李天宇', 80), ('陈扬', 73)]
# ── lambda + map:对列表每个元素统一处理 ──
scores = [60, 70, 80, 90]
boosted = list(map(lambda s: s + 5, scores))
print(boosted) # [65, 75, 85, 95] 每人加5分
10
初学者最容易犯的错误--- 错误代码 vs 正确代码对比
🚨 5 大高频错误清单
| # | 错误类型 | ❌ 错误写法 | ✅ 正确写法 |
|---|---|---|---|
| 1 | 定义了不调用 | def say(): print("Hi") 程序结束没输出 | 末尾加 say() 才执行 |
| 2 | 调用时忘写括号 | print(say) 打印的是函数对象,不是结果 | print(say()) |
| 3 | return后还写代码 | return x print("never") return后的代码永远不执行 | 把 print 移到 return 之前 |
| 4 | 忘了接收返回值 | add(3, 5) 结果算完就消失了 | result = add(3, 5) |
| 5 | 函数外用局部变量 | 函数内定义 x,外面 print(x) NameError 报错 | 用 return x 把值传出来 |
common_mistakes.py --- 错误演示与修正
# ── 错误1:定义了不调用(无输出)──
def say():
print("Hello")
# 以上代码运行不会输出任何东西!必须加:
say() # ✅ 这样才会输出 Hello
# ── 错误2:忘写括号 ──
def get_name():
return "黎俊杰"
print(get_name) # ❌ 输出:<function get_name at 0x...>
print(get_name()) # ✅ 输出:黎俊杰
# ── 错误4:忘了接收返回值 ──
def add(a, b):
return a + b
add(3, 5) # ❌ 计算了但没存,结果消失!
result = add(3, 5) # ✅ 存起来才能用
print(result) # 8
# ── 错误5:函数外使用局部变量 ──
def calc():
x = 42 # 局部变量,只在函数内
return x # ✅ 用 return 把它传出来
# print(x) # ❌ NameError!
print(calc()) # ✅ 42
📌
快速参考卡--- 撕下来贴墙上
Python 函数速查卡 # 定义 def 函数名(参数): 函数体(缩进4格) return 结果 # 调用 变量 = 函数名(实参) # 参数类型速查 def f(必填, 默认=值, *args, **kwargs) # lambda 一行函数 f = lambda x: x * 2 # 作用域 全局变量 → 函数内外都能读 局部变量 → 只在函数内部存在 global 变量名 → 在函数内修改全局变量
🧩 自测题 --- 做完才算真懂了!
Q1:下面代码输出什么?
def add(a, b=10): return a + b
print(add(5))
输出:15。a=5,b 用默认值 10,5+10=15。
Q2:函数里的局部变量,在函数外面能直接使用吗?为什么?
不能。 局部变量的生命周期只在函数内部,函数执行结束后就销毁了。 在外面访问会报 NameError。 如果想在外面用这个值,需要用 return 把它传出来。
Q3:什么时候用 lambda,什么时候用 def?
用 lambda: 逻辑只有一行,临时使用,常见于 sort/map/filter 的 key 参数。
**用 def:**逻辑超过一行,需要复用、需要写文档字符串,优先用 def。 原则:简单 → lambda,复杂 → def。
Q4:写一个函数 greet_all(names),接收一个名字列表,打印每人的问候语。
def greet_all(names): for name in names: print(f"你好,{name}!欢迎来到数据2001班!") greet_all("李俊杰", "周洁伦", "刘的话", "陈东东", "徐嘻嘻")