当前位置: 首页 > news >正文

Python 函数:从“是什么”到“怎么用”的完整指南

函数是 Python 世界里的第一等公民。掌握它,就掌握了把复杂度关进笼子里的钥匙。


一、为什么需要函数

  1. 复用:写一次,用 N 次。

  2. 抽象:把“怎么做”隐藏,只暴露“做什么”。

  3. 测试:最小可测单元,方便单元测试。

  4. 组合:乐高式地拼出更大的功能。

二、函数的本质:可调用的对象

在 Python 里,一切皆对象,函数也不例外。

>>> def add(a, b): return a + b
>>> type(add)
<class 'function'>
>>> add.__call__(3, 4)   # 函数对象内部实现了 __call__
7

因此函数可以:

  • 赋值给变量

  • 放进列表 / 字典

  • 作为参数或返回值

 三、定义函数:语法全景图

def 函数名([参数列表]) -> 返回注解:"""可选的文档字符串"""函数体[return 表达式]
  • 函数名:遵循蛇形命名 snake_case,动词优先。

  • 冒号 + 缩进 代替 C/Java 的花括号。

  • return 可省略,此时隐式返回 None

  • 注解 只是元数据,可被 __annotations__ 查看,不做运行时检查。

 四:参数类型全景

 1.位置参数(Positional-only Arguments,最“老实”的参数)
这是最传统、最没有花样的参数形态:你在定义时写一个名字,调用时按先后顺序把值塞进去即可。它既不能跳过,也不能用关键字“点名”。例如 def power(base, exponent),调用时必须写 power(2, 3),不能写 power(base=2, exponent=3)——顺序一旦写错,结果就南辕北辙。位置参数的好处是直观、高效;坏处是当参数一多,可读性会骤降,因此 Python 3.8 引入了“仅限位置参数”的语法符号 /,把这一风格显式化:

def tag(name, content, /):return f"<{name}>{content}</{name}>"

 2.默认值参数(Default Argument Values,给参数一个“备胎”)
有时某个参数在大多数场景里都是一个固定值,为了避免每次调用都重复书写,可以给它一个默认值。语法是在形参后加 = 和一个表达式。注意:表达式只在函数定义时求值一次,如果默认值是可变对象(列表、字典、集合),就可能踩到“共享陷阱”。典型写法:

def connect(host, port=3306, timeout=5):...

调用时可以省略已有默认值的参数:connect('db.example.com')connect('db.example.com', 5432)。默认值参数必须放在位置参数之后,否则解释器无法分辨谁是谁。

 3.可变位置参数(Var-Positional,*args)
当你不确定调用者会传多少个位置参数,或者想让它“想传几个就传几个”时,可以在形参名前加一个星号 *。Python 会把所有多余的位置实参打包成一个元组,绑到这个形参上。函数内部可以像遍历普通元组一样遍历 args

def mean(*values):return sum(values) / len(values) if values else 0.0

 调用示例:mean(1, 2, 3, 4)mean() 都合法。它带来的好处是接口极致简洁,坏处是静态类型检查工具(如 mypy)无法推断每个元素的具体类型,需要额外标注 Tuple[int, ...]

 4.可变关键字参数(Var-Keyword,**kwargs)
*args 类似,但收集的是“关键字实参”。在形参名前加两个星号 **,Python 会把所有未匹配的关键字实参打包成一个字典。典型场景是“透传”参数,如写装饰器时把上层收到的不确定关键字参数全部交给被装饰函数:

def trace(func, *args, **kwargs):print(f"Calling {func.__name__} with {args} and {kwargs}")return func(*args, **kwargs)

 调用示例:trace(open, 'file.txt', mode='wb', buffering=0)。字典键都是字符串,值可以是任意对象。

5.仅限关键字参数(Keyword-Only Arguments,用星号“隔出”的参数)
有时候你希望强制调用者用关键字形式传参,以提升可读性或防止顺序写错。做法是在参数列表里放一个裸星号 *,它之后的所有参数都必须用关键字传递。 

def create_user(username, *, is_admin=False, send_welcome=True):...

 调用时必须写 create_user('alice', is_admin=True),而不能写 create_user('alice', True)。这一特性在写配置类 API 时尤为有用,能避免“布尔陷阱”。

6.仅限位置参数

 与第 5 点相反,/ 之前的参数禁止用关键字形式传递。其目的在于让库作者未来能自由重命名这些参数而不破坏向后兼容。例如 CPython 内置函数 divmod(a, b) 就把两个参数都设为仅限位置,所以我们只能写 divmod(10, 3),而不能写 divmod(a=10, b=3)

7.解包调用

虽然它发生在调用端而非定义端,但经常与上述参数类型一起出现,因此一并说明。你可以在调用函数时使用 * 把序列/可迭代对象解包成位置实参,用 ** 把字典解包成关键字实参。 

coords = (4, 5)
point = {'x': 10, 'y': 20}
move_to(*coords)          # 等价于 move_to(4, 5)
create_point(**point)     # 等价于 create_point(x=10, y=20)

 当序列长度与形参数量不匹配时会抛出 TypeError,需要保证一一对应。

五、参数传递机制:共享传参(Call by Object Reference)

  • Python 没有真正的“值传递”或“引用传递”。

  • 形参 = 实参对象的 新引用

  • 若对象可变,原地修改对外部可见;若不可变,重新绑定不影响外部。

def append_one(xs):xs.append(1)          # 列表可变,外部可见
def set_zero(x):x = 0                 # 整数不可变,外部无感lst = []
append_one(lst); print(lst)  # [1]
n = 42
set_zero(n); print(n)        # 42

六、高级话题速览

  • 高阶函数

    map / filter / functools.reduce / sorted(key=...)

  • 闭包与延迟绑定陷阱

fs = [lambda: i for i in range(3)]
print([f() for f in fs])   # [2, 2, 2]
# 修复:lambda i=i: i
  • 装饰器

    本质是“函数返回函数”,加上 @ 语法糖。

  • 单分派泛函数

    @functools.singledispatch 实现 C++ 风格重载。

  • 类型提示与静态检查

from typing import List, Callable
def pipeline(data: List[int], fn: Callable[[int], int]) -> List[int]: ...

七、最佳实践清单

  • 单一职责:一个函数只做一件事。

  • 早返回(return early)减少嵌套。

  • 使用 dataclassesNamedTuple 替代裸字典返回。

  • 文档字符串格式:"""Do X and return Y.""" 或 Google / NumPy 风格。

  • 对可变默认值使用 None 占位:

def append(item, seq=None):if seq is None:seq = []

八、小结

函数是 Python 抽象、组合、复用的核心。
从最简单的 def 到装饰器、闭包、类型提示,每一步都让代码更声明式、更可测试

http://www.lryc.cn/news/588915.html

相关文章:

  • QT 中各种坑
  • 【Qt】QWidget核心属性
  • Django基础(二)———URL与映射
  • WSI中sdpc格式文件学习
  • 函数柯里化详解
  • 知识增强型Agent开发新范式:基于ERNIE-4.5的检索增强生成架构实践
  • ubuntu22.04 软创建 RAID1 与配置流程
  • Ubuntu 安装
  • Ubuntu环境下的K3S集群搭建
  • 一文读懂语义解析技术:从规则到神经网络的演进与挑战
  • DGNNet:基于双图神经网络的少样本故障诊断学习模型
  • 暑期算法训练.1
  • Linux下调试器gdb/cgdb的使用
  • 只解析了CHAME记录,如何申请免费的SSL证书
  • Linux 命令:passwd
  • WPF中ListView控件详解
  • 牛客:HJ23 删除字符串中出现次数最少的字符[华为机考][字符串]
  • Linux部署Python服务
  • langchain教程10:LCEL
  • 阿里云 Kubernetes 的 kubectl 配置
  • 深入理解设计模式之外观模式:简化复杂系统的艺术
  • 企业培训视频如何做内容加密防下载防盗录(功能点整理)
  • 优雅的Java:01.数据更新如何更优雅
  • 2025开放原子开源生态大会 | openKylin的技术跃迁和全球协作
  • 2025阿里云黑洞恢复全指南:从应急响应到长效防御的实战方案
  • CentOS服务器安装Supervisor使队列可以在后台运行
  • 2.3 数组与字符串
  • QGIS新手教程9:字段计算器进阶用法与批量处理技巧
  • HTTP性能优化实战技术
  • 串口通信性能优化