什么是工厂函数?
用函数来创建并返回对象或可调用物(函数/类实例/配置好的函数),把“怎么建、建什么”封装起来,对调用方只暴露一个统一入口。它是“工厂模式”的一种轻量 Python 实现。
1)最常见:对象工厂(替代直接 new)
class MySQL: ...
class Postgres: ...
def make_db(kind: str, **cfg):
if kind == "mysql":
return MySQL(**cfg)
if kind == "pg":
return Postgres(**cfg)
raise ValueError(f"unknown db kind: {kind}")
db = make_db("pg", host="127.0.0.1")
好处:屏蔽实现差异、集中校验与默认参数、便于切换和测试(可注入假实现)。
2)函数工厂(闭包返回“配置好”的函数)
def make_power(n: int):
def f(x: float) -> float:
return x ** n # 捕获 n
return f
square = make_power(2)
print(square(3)) # 9
场景:按配置生成处理器/校验器/中间件(计时、重试、限流等)。
3)注册表(插件式工厂,最常用在实际项目)
_REGISTRY: dict[str, type] = {}
def register(name: str):
def deco(cls):
_REGISTRY[name] = cls
return cls
return deco
@register("mysql")
class MySQL: ...
@register("pg")
class Postgres: ...
def make_db(kind: str, **cfg):
try:
return _REGISTRY[kind](**cfg)
except KeyError:
raise ValueError(f"unknown kind: {kind}")
优点:新增实现只需 @register,无需改工厂函数——开放封闭。
4)类工厂(动态生成类)
def make_model_class(name: str, base=object):
return type(name, (base,), {"version": 1})
UserV1 = make_model_class("UserV1")
用途:元编程/ORM/动态协议适配。
5)partial 当“函数工厂”
from functools import partial
def connect(host, port, timeout):
...
fast_connect = partial(connect, timeout=1.0) # 预配置一部分参数
6)与标准库的工厂位姿:default_factory
from dataclasses import dataclass, field
@dataclass
class Bag:
items: list[int] = field(default_factory=list) # 避免可变默认值坑
⸻
何时用工厂函数?
• 需要按配置或标识创建不同实现(数据库、存储、模型客户端)。
• 想要隐藏复杂构造(校验、默认值、依赖装配)。
• 需要可测试性/可替换性(注入 stub/mock)。
• 做插件化架构(注册表工厂)。
小坑与建议
• 错误提示要清晰:未知类型抛 ValueError,列出可选值。
• 避免分支爆炸:超过 3–4 个实现就改用“注册表模式”。
• 闭包晚绑定:工厂返回的函数若在循环中创建,注意用默认参数或额外一层函数定格变量。
• 类型提示:用 typing.Protocol 或 Union 标注返回类型,便于 mypy/pyright 检查。
from typing import Protocol
class DB(Protocol):
def query(self, sql: str) -> list: ...
def make_db(kind: str) -> DB: ...
——
一句话:工厂函数=“把创建细节装进函数”。它让调用方只关心“要什么”,而不用关心“怎么造”,非常适合可插拔、可测试的 Python 代码风格。
1万+

被折叠的 条评论
为什么被折叠?



