Python 函数
1. 函数基础:定义与抽象
函数不是什么玄乎的东西——它就是一段封装好、可重复调用、解决单一问题的代码块。从程序员的视角看,函数最核心的价值是抽象:比如不用每次都写“从1加到100的循环”,可以直接有sum();不用每次想三角函数,直接掏math.sin()就行。
1.1 标准定义语法
Python 用 def 关键字起手定义函数,现在的工业级代码都推荐加文档字符串(Docstring)和类型提示(Type Hints)——前者给调用者看“这函数干嘛”,后者给编辑器和静态检查工具看“传啥、返啥”,提升可维护性。
1.2 关于返回值的细节
- 单一返回:用
return直接扔结果就行。 - 多个返回:写
return x, y就够——Python 会自动把它们包成元组(tuple),调用时可以用多变量接收或者索引。 - 空占位:暂时没想好逻辑?用
pass占坑;没写return或者return后面空着?Python 默认返回None。
2. 函数调用:让代码块“动起来”
定义完函数,它只是躺在内存里的“静态模板”,必须通过调用才能执行。
2.1 三种基础调用姿势
2.2 重要的参数传递机制
别光记参数名字,搞懂Python怎么把值丢给函数很关键:
- 调用方式分两种:
- 位置调用:
f(a, b),严格按函数定义的顺序传值。 - 关键字调用:
area_of_circle(radius=5.0),清晰明了,参数多的时候还能乱序。
- 位置调用:
- 内存层面的本质:Python 是「对象引用传递」,不是纯「值传递」或纯「地址传递」:
- 传不可变对象(数字、字符串、元组):函数内部的赋值/修改只会创建新对象,不会碰外部变量。
- 传可变对象(列表、字典、集合):函数内部的原地修改(比如
.append()、.update())会同步影响外部变量!
2.3 快速动态调用(参数解包)
如果你的参数已经存在列表/元组、字典里,不用一个个拆,用 * 或 ** 就行:
3. 深入理解参数系统:规则让你更自由
Python 的参数系统非常灵活,但定义顺序必须严格遵守,不然会报错。下面按优先级整理成表格:
4. 递归函数:简化逻辑,但要注意边界
递归就是函数自己调用自己,核心思想是把复杂问题拆解成「结构完全相同但规模更小」的子问题。
4.1 经典入门案例:阶乘
4.2 递归的三个黄金守则
- 必须有明确的终止条件:比如上面的
n == 1,不然Python默认的1000层递归限制(sys.getrecursionlimit())会触发。 - 每次递归都要向终止条件靠近:比如每次把n减1,不能越算越大。
- 合理权衡性能:递归代码虽然简洁,但每次调用都会消耗函数调用栈的空间,对性能敏感的场景(比如计算超级大的斐波那契数),建议用迭代(循环)代替。
4.3 现代Python优化:记忆化缓存
很多递归(比如斐波那契)会重复计算相同的子问题,Python 3.9+ 提供了超级简单的解决方案——直接加装饰器就行!
5. 工业级最佳实践与规范
写好函数不仅要能跑,还要好读、好改、好复用:
- 单一职责原则:一个函数只解决一个问题,比如不能同时“计算面积并打印并保存到文件”。
- 命名规范:全小写加下划线,动词开头(比如
calculate_tax、validate_input)。 - 参数验证:在函数开头用
isinstance()检查类型,用条件语句检查范围,不对就抛明确的异常(比如TypeError、ValueError)。 - 尽量避免副作用:别在函数内部修改全局变量,别原地修改传入的可变对象——如果必须改,要么文档里写清楚,要么返回一个新的修改后的对象。
6. 综合实战:一元二次方程求解器
把前面的知识点串起来,写一个符合规范的工具函数:
7. 总结
函数是Python编程的核心基石:基础的定义调用能让代码不重复,灵活的参数系统能适配各种场景,递归能简化复杂逻辑但要注意边界,记忆化缓存能提升重复计算的效率。最后别忘了遵循最佳实践——这样你的代码才能从“能跑”变成“好用”。

