Python: 参数进阶与作用域

最后更新:2026-09-22

函数基础学会了,这一课来点进阶技巧。参数有多少种写法?"变量作用域"是什么意思?递归又是什么?这些概念掌握后,你对函数的理解会上一个台阶。


相关关键字与语句:return global print None len

1. 默认参数

给参数指定默认值,调用时可以不传:

▶ 示例:默认参数基本用法

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功

(1) ⚠️ 默认参数的陷阱

默认参数的值只在函数定义时计算一次,而不是每次调用时。如果默认值是可变对象(如列表、字典),会有意想不到的行为:

▶ 示例:可变默认参数的陷阱

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功

原因: items=[] 这个空列表在函数定义时创建了一次,之后的每次调用都在同一个列表上追加。

正确做法: 用 None 作为默认值,在函数内部创建新列表:

▶ 示例:安全的默认参数写法

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功
💡 黄金法则: 默认参数永远用不可变值(None、数字、字符串、元组)。不要用列表、字典等可变对象做默认值。



2. 关键字参数

调用函数时,可以通过参数名来指定值,这样可以不按顺序传参:

▶ 示例:关键字参数调用

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功


3. *args:可变位置参数

如果你不确定函数会接收多少个参数,用 *args:

▶ 示例:*args 实现求和函数

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功

*args 把所有传入的位置参数打包成一个元组:

▶ 示例:查看 args 中的参数

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功


4. **kwargs:可变关键字参数

**kwargs 接收任意多个关键字参数,打包成一个字典:

▶ 示例:**kwargs 构建用户资料

▶ 试一试

运行结果:

TEXT 📖 仅展示
用户资料:
  name:Alice
  age:25
  city:北京
  job:工程师

▶ 示例:综合使用 *args 和 **kwargs

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功
💡 参数顺序必须固定: 普通参数 → *args → 默认参数 → **kwargs



5. 作用域:LEGB 规则

变量在函数的什么位置能访问?这由作用域决定。Python 有四个层级的作用域:

▶ 示例:LEGB 作用域嵌套

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功

LEGB 代表:

Python 按 L → E → G → B 的顺序查找变量。

(1) global 和 nonlocal

如果你想在函数内部修改全局变量,用 global:

▶ 示例:使用 global 修改全局变量

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功
⚠️ 尽量少用 global。 全局变量让代码变得难以理解和调试。函数应该通过参数接收输入,通过 return 返回输出,而不是偷偷修改全局变量。



6. 递归入门

递归就是函数调用自己。递归的核心是:把一个大问题拆成更小的同类问题。

▶ 示例:递归计算阶乘

▶ 试一试

执行过程:

TEXT 📖 仅展示
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

▶ 示例:斐波那契数列(难度⭐⭐⭐)

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功
💡 递归的两大要素: ① 终止条件(不然会无限递归 → 栈溢出)。② 递归条件(每次调用都让问题更接近终止条件)。不是所有问题都适合递归——循环能解决的问题,优先用循环。递归适合树形结构、分治算法等场景。



7. 常见应用场景


相关关键字与语句:return global print None len

❓ 常见问题

Q *args 和可变关键字解包语法的名字可以改吗?
A 可以。*args 和双星号关键字解包只是约定俗成的命名——星号才是关键。你也可以写成 *numbers,或用双星号配 options。但建议遵循惯例——其他 Python 程序员一看就懂。
Q 递归和循环哪个好?
A 能用循环解决的问题,优先用循环。循环性能更好、不会栈溢出、更容易理解。递归适合两个场景:树形结构的遍历(目录、JSON)和数学定义本身就是递归的(阶乘、斐波那契)。递归写起来更简洁,但理解起来更难。
Q 为什么函数内可以直接读取全局变量但不能修改?
A 读取时,Python 按 LEGB 规则找到全局变量。但赋值时,Python 默认在局部作用域创建新变量——x = 10 在函数内会被当作"创建局部变量 x"。如果你确实要修改全局变量,用 global 声明。但这通常意味着你的设计可能需要改进。

📖 小节


📝 作业

  1. 基础题(难度⭐):写一个函数 multiply(*nums),接收任意多个数字,返回它们的乘积。如果没传参数,返回 0。

  2. 进阶题(难度⭐⭐):写一个函数 create_student(name, **scores),接收学生姓名和任意多门科目的成绩(关键字参数),计算并返回该学生的平均分。调用示例:create_student("Alice", 语文=85, 数学=92, 英语=78)。

  3. 挑战题(难度⭐⭐⭐):写一个递归函数 sum_digits(n),计算一个正整数各位数字之和。例如 sum_digits(123) 返回 1+2+3=6。提示:对 10 取余得到个位数,对 10 整除去掉个位数。终止条件是 n < 10。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏