Python: 参数进阶与作用域
最后更新:2026-09-22
函数基础学会了,这一课来点进阶技巧。参数有多少种写法?"变量作用域"是什么意思?递归又是什么?这些概念掌握后,你对函数的理解会上一个台阶。
1. 默认参数
给参数指定默认值,调用时可以不传:
▶ 示例:默认参数基本用法
▶ 试一试输出:
# 函数定义成功
(1) ⚠️ 默认参数的陷阱
默认参数的值只在函数定义时计算一次,而不是每次调用时。如果默认值是可变对象(如列表、字典),会有意想不到的行为:
▶ 示例:可变默认参数的陷阱
▶ 试一试输出:
# 函数定义成功
原因: items=[] 这个空列表在函数定义时创建了一次,之后的每次调用都在同一个列表上追加。
正确做法: 用 None 作为默认值,在函数内部创建新列表:
▶ 示例:安全的默认参数写法
▶ 试一试输出:
# 函数定义成功
None、数字、字符串、元组)。不要用列表、字典等可变对象做默认值。
2. 关键字参数
调用函数时,可以通过参数名来指定值,这样可以不按顺序传参:
▶ 示例:关键字参数调用
▶ 试一试输出:
# 函数定义成功
3. *args:可变位置参数
如果你不确定函数会接收多少个参数,用 *args:
▶ 示例:*args 实现求和函数
▶ 试一试输出:
# 函数定义成功
*args 把所有传入的位置参数打包成一个元组:
▶ 示例:查看 args 中的参数
▶ 试一试输出:
# 函数定义成功
4. **kwargs:可变关键字参数
**kwargs 接收任意多个关键字参数,打包成一个字典:
▶ 示例:**kwargs 构建用户资料
▶ 试一试运行结果:
用户资料:
name:Alice
age:25
city:北京
job:工程师
▶ 示例:综合使用 *args 和 **kwargs
▶ 试一试输出:
# 函数定义成功
普通参数 → *args → 默认参数 → **kwargs
5. 作用域:LEGB 规则
变量在函数的什么位置能访问?这由作用域决定。Python 有四个层级的作用域:
▶ 示例:LEGB 作用域嵌套
▶ 试一试输出:
# 函数定义成功
LEGB 代表:
- Local(局部)—— 当前函数内部
- Enclosing(外层)—— 外层函数的局部
- Global(全局)—— 模块级别
- Built-in(内置)—— Python 内置函数(如
print、len)
Python 按 L → E → G → B 的顺序查找变量。
(1) global 和 nonlocal
如果你想在函数内部修改全局变量,用 global:
▶ 示例:使用 global 修改全局变量
▶ 试一试输出:
# 函数定义成功
global。 全局变量让代码变得难以理解和调试。函数应该通过参数接收输入,通过 return 返回输出,而不是偷偷修改全局变量。
6. 递归入门
递归就是函数调用自己。递归的核心是:把一个大问题拆成更小的同类问题。
▶ 示例:递归计算阶乘
▶ 试一试执行过程:
factorial(5) = 5 * factorial(4)
= 5 * 4 * factorial(3)
= 5 * 4 * 3 * factorial(2)
= 5 * 4 * 3 * 2 * factorial(1)
= 5 * 4 * 3 * 2 * 1
= 120
▶ 示例:斐波那契数列(难度⭐⭐⭐)
▶ 试一试输出:
# 函数定义成功
7. 常见应用场景
- 默认参数:配置选项、超时时间、回调函数等场景。
- *args:数学聚合函数(sum、average)、日志格式化。
- *kwargs:函数包装器、配置合并、数据库查询参数构建。
- 递归:目录树遍历、JSON 多层嵌套解析、数学公式(阶乘/斐波那契)。
- 作用域:理解闭包(下一课)、理解变量生命周期。
❓ 常见问题
*args 和可变关键字解包语法的名字可以改吗?*args 和双星号关键字解包只是约定俗成的命名——星号才是关键。你也可以写成 *numbers,或用双星号配 options。但建议遵循惯例——其他 Python 程序员一看就懂。x = 10 在函数内会被当作"创建局部变量 x"。如果你确实要修改全局变量,用 global 声明。但这通常意味着你的设计可能需要改进。📖 小节
- 默认参数让函数更灵活,但不要用可变对象做默认值
- 关键字参数让你不必记住参数顺序,可以按名传参
*args打包多余位置参数为元组,**kwargs打包关键字参数为字典- 参数顺序:普通参数 →
*args→ 默认参数 →**kwargs - LEGB 规则决定变量的查找顺序:局部→外层→全局→内置
global在函数内修改全局变量,尽量少用- 递归是函数调用自身,需要终止条件和递归条件
📝 作业
-
基础题(难度⭐):写一个函数
multiply(*nums),接收任意多个数字,返回它们的乘积。如果没传参数,返回 0。 -
进阶题(难度⭐⭐):写一个函数
create_student(name, **scores),接收学生姓名和任意多门科目的成绩(关键字参数),计算并返回该学生的平均分。调用示例:create_student("Alice", 语文=85, 数学=92, 英语=78)。 -
挑战题(难度⭐⭐⭐):写一个递归函数
sum_digits(n),计算一个正整数各位数字之和。例如sum_digits(123)返回1+2+3=6。提示:对 10 取余得到个位数,对 10 整除去掉个位数。终止条件是 n < 10。