基础篇 · Foundations
lv.1 入门
kp-007
函数基础(def、参数、作用域)
1. 一句话定义
函数用 def 定义,参数系统支持位置/关键字/默认/可变参数四种组合,作用域遵循 LEGB 规则;最大陷阱是可变默认值。
2. 为什么重要
函数是复用的最小单元,参数设计与作用域规则直接决定代码质量。可变默认值陷阱几乎出现在每一份 Python 面试题里,也是真实事故源。
3. 前置知识
kp-003(名字绑定——作用域与传参都是它的延伸)、kp-006。
4. 核心概念
- 参数五种:位置参数、关键字参数、默认值参数、
*args(收集多余位置参数)、**kwargs(收集多余关键字参数)。 - 仅限位置
/与仅限关键字*(3.8+):显式声明调用约定,让 API 稳定。 - 作用域 LEGB:Local → Enclosing → Global → Builtin,逐层向外查找。
- 返回:无
return等价return None;可返回元组实现"多返回值"。
5. 原理与机制
python
def report(title, *lines, sep=" | ", indent=True):
"""title 为必选位置参数;*lines 收集成元组;sep 是仅限关键字参数"""
body = sep.join(lines)
return f"{title}: {body}"
report("日志", "启动", "完成") # 日志: 启动 | 完成
report("日志", "a", "b", sep=", ", indent=False) # 关键字调用
def add(a, b, /, c, *, d=0): # a,b 仅限位置;d 仅限关键字
return a + b + c + dLEGB 与 nonlocal/global:
python
counter = 0
def make():
n = 0
def step():
nonlocal n # 声明改写外层(闭包话题见 kp-023)
n += 1
return n
return step可变默认值陷阱与修复:
python
# ✗ 错误:默认列表只创建一次,所有调用共享
def add_item(item, items=[]):
items.append(item)
return items
# ✓ 正确:哨兵 None,函数体内新建
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items原理:默认值表达式在 def 执行时求值一次,绑定到函数对象的 __defaults__,之后每次调用复用同一对象(kp-003 的"对象共享"重演)。
6. 关键事实(模型/图示)
text
调用 f(1, x=2):
位置参数按序填 → 关键字按名填 → 未填的取默认 → 多余的进 *args/**kwargs
传参 = 名字绑定:形参名绑定到实参对象(不做复制)类型注解(def f(x: int) -> str:)是可选的、运行时不上锁,见 kp-026。
7. 直观类比
默认值像餐厅的公共小料台:[] 是一盆真实的公共小料,谁来加一勺都动同一盆;正确写法是"每位客人下单时现做一份新的"。
8. 实例与案例
python
def find(*, value, data, key=lambda x: x): # 强制关键字调用,可读性
return next((x for x in data if key(x) == value), None)
find(value=2, data=[1, 2, 3]) # 必须写参数名,调用点自文档化9. 常见误区
- 可变默认值(上文)——最高频。
- 以为传参会复制对象 —— 只是绑定(kp-003);函数内
append调用方可见,重新赋值不可见。 - 函数内赋值就想改全局 —— 默认是局部;要改全局须
global,改外层须nonlocal;能不写就不写(可读性)。 - 把
lambda当万能短函数 —— 只能单表达式,复杂逻辑用def;做排序 key 是它的正当场景。
10. 自测题
def f(a, b=2, *args, c, d=3): ...中哪些参数必须显式提供?- 如何让一个函数强制调用者写参数名?强制不写参数名呢?
- 为什么
def f(x, acc=[])危险?给出两种修复方式。
参考答案
a、c(无默认值的位置参数和仅限关键字参数)。- 参数列表里加
*之后仅限关键字(如*, c);加/之前仅限位置。 - 默认值仅求值一次并被共享,跨调用累积;修复:默认
None+ 体内新建,或用不可变默认配合显式重建。
11. 与其他知识点的关系
12. 延伸阅读
- Python 官方教程 §4.7 Defining Functions
- PEP 570(仅限位置参数)