Function (函数)
函数(function) 是一段可复用的代码块,用来执行特定任务。
函数可以:
- 接收参数
- 返回值
- 内部执行逻辑
- 封装行为,提高复用性
最基础例子:
def add(a, b):
return a + b
调用:
add(1, 2)
def 函数名(参数列表):
函数体
return 返回值
例:
def greet(name: str) -> str:
return f"Hello, {name}"
Python 函数支持 多种参数类型:
def add(a, b):
return a + b
def connect(host="localhost", port=3306):
...
def total(*nums):
return sum(nums)
total(1,2,3)
def debug(**info):
print(info)
debug(a=1, b=2)
def config(*, debug=False):
print(debug)
必须写成:
config(debug=True)
def func(a, b, *args, c=1, d=2, **kwargs):
...
def foo():
return 123
多个返回:
def get_info():
return "jack", 18
name, age = get_info()
返回 None:
def log(msg):
print(msg)
# 默认 return None
在 Python 里,函数本质上是对象,类型是:
import types
type(func) == types.FunctionType
函数可以:
- 赋值
- 存入 dict
- 作为参数传递
- 作为返回值返回
例:
def a():
print("a")
b = a
b()
def apply(func, x):
return func(x)
def double(n):
return n * 2
apply(double, 5) # 10
square = lambda x: x * x
常用于 map/filter/sorted:
sorted(data, key=lambda x: x["age"])
闭包 = 内层函数 + 外层作用域变量
def make_adder(n):
def adder(x):
return x + n
return adder
add5 = make_adder(5) add5(10) # 15
装饰器本质是高阶函数:
def log(func):
def wrapper(*a, **kw):
print(f"Run {func.__name__}")
return func(*a, **kw)
return wrapper
使用:
@log
def run():
pass
普通函数:一次返回 生成器:逐次返回,惰性计算
def gen():
yield 1
yield 2
async def fetch(url):
...
配合 await:
data = await fetch(url)
你的 FastAPI 项目常用的就是 async 函数。
def f(a, b, c):
...
args = (1,2,3)
f(*args)
kwargs = {"a":1,"b":2,"c":3}
f(**kwargs)
函数调用自己:
def fact(n):
return 1 if n==0 else n * fact(n-1)
LEGB 规则:
- Local(局部)
- Enclosing(外层函数)
- Global(模块)
- Built-in(内置)
例:
x = 10 # global
def outer():
x = 20 # enclosing
def inner():
x = 30 # local
def add(a: int, b: int) -> int:
return a + b
- 逻辑小而清晰
- 使用类型注解提高可读性
- 参数使用 dict 时优先加类型别名:dict[str, Any] 或 TypedDict
- 尽量保持函数纯净(无副作用)
- 把大函数拆分为多个小函数
- 配合装饰器统一异常处理、性能监控、日志
- 尽量避免使用全局变量
- 输入参数要先校验(你正在做)
用函数:
- 非复杂逻辑
- 不需要状态
- 不需要多次复用内部数据
- utils 工具类中的大部分都可以用函数
用类:
- 需要保存状态(数据库连接池 / 配置对象)
- 需要扩展性
- 需要继承
- 需要 property、static、class 等丰富接口
| 领域 | 内容 |
|---|---|
| 基础 | def / 参数 / return |
| 进阶 | *args / **kwargs / lambda |
| 高阶 | 装饰器 / 闭包 / 上下文管理 |
| 异步 | async / await |
| 惰性 | yield 生成器 |
| 工程 | 类型注解 / 函数式编程 / 模块化设计 |
下面是一份 真正项目级的《Python 定义函数最佳实践(最强完整版)》
同时结合你长期的代码风格(FastAPI + SQLAlchemy + 工具函数为主),给出最实用、最现代、最强类型、可维护性优秀的标准。
内容涵盖:
- 命名规范
- 参数设计
- 返回值
- 类型注解
- 文档注释
- 错误处理
- 性能优化
- 函数式工具
- 模块封装
- 何时用类、何时用函数
| 场景 | 命名方式 | 示例 |
|---|---|---|
| 动作型函数 | 动词开头 | get_user、save_data |
| 工具函数 | 动词 + 名词 | to_datetime、to_json、map_filter |
| 转换函数 | to_ / from_ |
to_dict、from_row |
| 判断函数 | is_ / has_ / should_ |
is_valid、has_permission |
| 私有函数 | 前置下划线 | _parse_row、_clean_title |
✅ 为别人阅读代码时“意图可见”。
不好:
def create(x, y, z, a, b):
...
好:
def create(*, user, title, content, tags=None):
...
关键字参数具有:
- 可读性好
- 调用更安全
- 修改参数顺序时不破坏调用方
def fetch(limit: int | None = None):
...
❌ 绝对不要:
def fn(data=[]):
...
✅ 使用 None:
def fn(data=None):
if data is None:
data = []
from typing import Any
def sum_all(*nums: int) -> int:
return sum(nums)
不要这样:
def get_user():
return user or False
应该这样:
def get_user() -> User | None:
return user
✅ 更易读,和类型检查工具兼容:
return None
保持 API 兼容性是非常重要的。
你已经明确要求:
- Python ≥ 3.12
- 禁止使用 typing 中的已废弃类型
因此应该遵循:
def fn(x: list[str]) -> dict[str, int]:
...
from collections.abc import Iterable, Callable
def map_filter(iterable: Iterable[T], func: Callable[[T], R]) -> list[R]:
...
def run_task(task: Task) -> bool:
...
例如:
def parse(dt: str) -> datetime.datetime:
...
请使用 Google 风格或 NumPy 风格,不要使用随意风格。
推荐 Google 风格:
def to_datetime(s: str) -> datetime:
"""
Convert a datetime string to datetime object.
Args:
s: datetime string in "%Y-%m-%d %H:%M:%S" format.
Returns:
Parsed datetime object.
Raises:
ValueError: if the string cannot be parsed.
"""
❌ 不要这样:
try:
...
except Exception:
return None
你会屏蔽一切异常,不利排查。
✅ 正确做法:捕获明确的异常
try:
x = int(s)
except ValueError:
logger.error(...)
return None
以下规则非常重要(你的项目用得上):
def gen_items():
for i in range(10):
yield i
cleaned = list(map(clean, rows))
pattern = re.compile(...)
不要:
re.search("xxx", text) # 每次都编译
(你已经开始使用 map_filter,非常棒)
推荐你使用:
- map_filter
- filter_map
- compose
- pipe
- safe_get
- find_first(基于 next)
我们可以封装一个完整模块:utils.functional
每次写函数前,请问自己:
- 这个函数的唯一职责是什么?(SRP)
- 需要类型强约束吗?
- 对调用方是否友好?
- 是否可以测试?
- 是否需要文档?
- 是否必须兼容旧字段?
- 是否要保证确定性(稳定输出)?
使用类(Class)——当状态很重要时:
- 数据库 Session 管理
- 配置对象
- 服务对象(Service)
- 有生命周期逻辑
- 依赖注入
使用函数(Function)——当操作是无状态时:
- 文本处理
- 数据转换
- 解析器
- 验证器
- 工具函数
你已经非常明确:utils 模块适合函数式设计。
- 函数命名清晰、语义明确
- 参数使用 keyword-only
- 默认参数避免可变类型
- 返回值类型清晰(不要 False 表示失败)
- 使用类型注解(Python 3.12 风格)
- 适度使用 map/filter/next 函数式处理
- 提供有意义的 docstring
- 避免重复构造对象
- 工具函数模块化封装