Python def 定义函数的基本语法与规范
def 关键字,但写出一个易读、稳定且符合工程标准的函数,不仅需要掌握缩进、参数绑定与返回值机制,还必须遵循 PEP 8 命名规范及避免可变默认参数等常见陷阱。
一、def 关键字与函数声明的基本语法
定义 Python 函数的起点是保留字 def(define 的缩写)。它通知解释器正在创建一个新的函数对象,并将其绑定到指定的函数标识符上。标准的函数定义由关键字、函数名称、形参列表、结尾冒号、可选的文档字符串(Docstring)以及缩进的函数体组成。
基本语法的骨架如下所示:
def function_name(parameter_1, parameter_2=default_value):
"""
简要说明该函数的功能与行为。
参数:
parameter_1: 位置参数说明
parameter_2: 带有默认值的参数说明
返回:
计算或处理后的结果
"""
# 具体的执行逻辑
computed_result = parameter_1 + parameter_2
return computed_result
在解析这段语法时,有四个必须严格遵守的语法规则:
- 冒号不可或缺:参数括号后的冒号
:标志着函数头部的结束,同时也是开启缩进代码块的语法标志。 - 严格缩进:函数体内的所有逻辑代码必须保持统一的缩进级别(官方推荐 4 个空格)。缩进层级的改变直接决定了代码是否属于函数内部。
- 文档字符串位置:若要为函数提供说明文档,三引号字符串必须紧接在定义头部之后、任何可执行语句之前。Python 会将其自动存入函数的
__doc__属性中。 - return 语句:用于终止函数执行并将指定结果交还给调用方。若未显式编写
return或仅写return后无表达式,函数将隐式返回None。
二、函数调用执行机制与生命周期
仅用 def 声明并不会执行函数体中的代码,它只是在内存中编译并注册了该函数对象。当程序运行到包含函数调用的表达式时,Python 解释器才会为本次调用分配专门的执行上下文(即局部命名空间与调用栈帧)。
一次标准的函数调用历经四个关键阶段:
- 实参求值与入栈:在调用位置解析传入的实际参数表达式,生成对应的对象引用。
- 栈帧建立与形参绑定:解释器在调用栈(Call Stack)上为该函数压入一个新的执行栈帧(Frame),创建局部变量命名空间,并将实参引用赋值给对应的形参名。
- 函数体顺序执行:代码从第一行缩进语句按控制流逻辑依次运行,期间产生的局部变量仅在此作用域中可见。
- 返回结果与栈帧弹出:遇到
return语句后,计算返回对象,将返回值移交调用者,随后局部栈帧被销毁,未被外部引用的局部对象进入垃圾回收机制。
三、参数定义的五种形式与顺序规范
Python 提供了极具表达力的形参定义体系,但在同一个函数头部组合使用时,必须严格按照语法规定的先后顺序排列。否则,Python 会直接报出语法错误(SyntaxError: non-default argument follows default argument)。
1. 参数种类的排列先后
函数形参列表的标准声明顺序严格遵从以下 5 个阶段:
- 位置参数(Positional Arguments):调用时必须按照位置一一传入的核心形参,例如
x, y。 - 默认参数(Default Arguments):预先设定缺省值的参数,例如
z=0。所有默认参数必须排在无默认值的位置参数之后。 - 可变位置参数(*args):使用一个星号接收任意数量多余的位置实参,在函数内被打包为元组(tuple)。
- 命名关键字参数(Keyword-only Arguments):出现在
*args之后或者裸星号*之后的形参,调用时必须显式指定参数名赋值。 - 可变关键字参数(**kwargs):使用两个星号接收任意数量未定义的关键字实参,在函数内被打包为字典(dict),必须置于形参列表最末尾。
# 标准组合范例:展示完整的参数定义顺序
def standard_func(req_pos, opt_pos=10, *args, kw_only, opt_kw="default", **kwargs):
print(f"必选位置形参: {req_pos}")
print(f"可选默认形参: {opt_pos}")
print(f"多余位置实参元组: {args}")
print(f"必选命名关键字形参: {kw_only}")
print(f"可选命名关键字形参: {opt_kw}")
print(f"多余关键字实参字典: {kwargs}")
重要避坑提醒:绝不要使用可变对象作为默认值
Python 的默认参数在函数定义时(即编译加载阶段)被求值并创建一次,而不是在每次调用时重新生成。若使用列表、字典或集合等可变对象(Mutable Object)作为默认值,后续调用的修改将在所有调用间持久共享,导致严重的数据污染。
# 危险做法:列表在多次调用中持续累积
def append_item_bad(val, target_list=[]):
target_list.append(val)
return target_list
# 正确规范做法:使用 None 并在函数体内按需初始化
def append_item_good(val, target_list=None):
if target_list is None:
target_list = []
target_list.append(val)
return target_list
四、返回值与控制流设计规范
函数通过 return 语句将结果传递给外部。在返回值的设计上,清晰、可预测是首要原则。
1. 多值返回的本质是元组
在 Python 中可以写出类似同时返回多个变量的语法:
def get_coordinates():
x = 10.5
y = 20.8
return x, y # 逗号将两个变量打包成元组
# 调用处解包
pos_x, pos_y = get_coordinates()
需要注意的是,Python 并没有原生支持返回多个分散对象的机制,这里的多值返回本质上是利用了逗号表达式隐式构造了一个不可变元组 (x, y),并在赋值端通过解包(Unpacking)分别绑定。
2. 卫语句(Guard Clauses)与尽早返回
避免深层嵌套的 if-else 结构是写出规范函数的核心技巧。一旦发现参数不合法或满足边界终止条件,应立即使用 return 退出,保持主体代码处于最浅缩进层级:
# 规范:使用卫语句进行尽早返回(Early Return)
def process_user_data(user):
if not user or not user.get("is_active"):
return None
if user.get("age", 0) < 18:
return {"status": "rejected", "reason": "underage"}
# 核心业务逻辑平铺展开,无多层缩进
profile = build_profile(user)
return {"status": "success", "profile": profile}
五、PEP 8 与现代工程规范
在团队开发和大型工程中,遵守 Python 官方 PEP 8 风格指南及相关增强提案能够极大降低维护成本。定义函数时应重点关注以下四大维度:
| 规范维度 | 推荐做法(Do) | 反面模式(Don't) |
|---|---|---|
| 函数命名 | 全小写加下划线(snake_case),动词或动宾短语,如 calculate_tax() |
驼峰命名或模糊无动作名,如 CalculateTax(), data() |
| 空行规范 | 顶层函数之间保留 2 个空行;类中方法之间保留 1 个空行 | 挤压在一起无空行,或随意使用多个空行 |
| 类型提示 | 使用 PEP 484 类型注解标明入参和返回类型,便于静态检查 | 完全缺失类型说明,迫使维护者阅读实现推测参数结构 |
| 单一职责 | 一个函数只完成一件事,函数体通常控制在 30-50 行以内 | 一个函数融合输入、计算、网络请求和数据库写入等全部职责 |
类型提示(Type Hints)的标准写法
自 Python 3.5 起引入的类型提示已成为现代 Python 开发的标配。使用冒号标明参数类型,使用箭头 -> 标明返回值类型:
from typing import Optional, List, Dict
def query_records(
db_name: str,
limit: int = 100,
tags: Optional[List[str]] = None
) -> Dict[str, int]:
"""
带有标准 PEP 484 类型提示与 PEP 257 文档字符串的规范函数。
"""
if tags is None:
tags = []
return {"total": len(tags), "status": 200}
六、总结
使用 def 定义函数是 Python 编程最基础的技能,也是构建高可靠度软件的核心基石。回顾整个设计闭环:
- 在语法层面,理解冒号、缩进与局部命名空间的生命周期;
- 在参数层面,严格遵守“位置参数 → 默认参数 → *args → 命名关键字 → **kwargs”的排列顺序,并始终使用不可变对象或
None配合条件判断来设定默认值; - 在工程层面,借助清晰的蛇形命名、类型注解与规范的 Docstring,使函数具备自解释能力,并利用尽早返回的原则保持逻辑平实清晰。
掌握这些基本语法与规范,不仅能消除语法错误与潜在隐患,更能让代码在团队协作和长期维护中保持卓越的可读性与健壮性。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









