You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python 3.10中如何为建造者模式make方法添加类型提示

问题结论

该需求在Python 3.10版本中完全可以实现,不需要升级Python版本,通过标准库typing模块提供的泛型能力即可完成,配置后mypy、PyCharm、VSCode(Pylance/Pyright)等类型检查/IDE工具都能正确推断make()方法的返回值类型,支持对应类的属性、方法自动补全,不会再被推断为None。

原先代码被推断返回None的原因是:基类AggregateMaker中没有声明_make方法的签名,类型检查器无法追踪self._make()的返回值类型,就会默认回退为None类型。


实现方案

核心思路是给AggregateMaker基类定义泛型参数,绑定子类_make方法返回的具体产品类型,同时给链式调用的new、with_方法标注正确的自身类型,避免链式调用时丢失类型信息。

第一步:导入依赖的类型构件

Python 3.10标准库自带所有需要的类型组件,不需要额外安装第三方包:

from dataclasses import dataclass
# 导入泛型相关类型
from typing import TypeVar, Generic, Any

第二步:定义类型变量

需要定义两个类型变量,分别标记最终生成的产品类型、Maker类自身的类型(用于链式调用返回值标注):

# 泛型参数:标记make方法最终返回的产品类型(Fruit/Tea等)
T = TypeVar("T")
# 泛型参数:标记Maker子类自身类型,解决链式调用的类型传递问题
M = TypeVar("M", bound="AggregateMaker[Any]")

第三步:改造基类为泛型类

给AggregateMaker添加泛型继承,给所有方法补充类型标注,同时在基类声明_make方法的接口,方便类型检查器识别返回值传递链路:

class AggregateMaker(Generic[T]):
    _fields: dict[str, Any]

    @classmethod
    def new(cls: type[M], **fields: Any) -> M:
        return cls(fields=None).with_(**fields)

    def make(self) -> T:
        return self._make(self._fields)

    # 基类声明_make接口,子类实现时自动绑定对应T类型
    def _make(self, fields: dict[str, Any]) -> T:
        raise NotImplementedError

    def with_(self: M, **overrides: Any) -> M:
        copy = dict(self._fields)
        for name, value in overrides.items():
            copy[name] = value
        return type(self)(copy)

第四步:子类指定泛型参数

子类继承基类时,在方括号中指定当前子类生成的具体产品类型即可,其余原有业务逻辑不需要改动:

# 指定泛型参数为Fruit
class FruitMaker(AggregateMaker[Fruit]):
    def __init__(self, fields: dict[str, Any] | None):
        if fields is None:
            fields = {
                "name": None,
                "smell": None,
            }
        self._fields = fields

    def _make(self, fields: dict[str, Any]) -> Fruit:
        return Fruit(**fields)

# 指定泛型参数为Tea
class TeaMaker(AggregateMaker[Tea]):
    def __init__(self, fields: dict[str, Any] | None):
        if fields is None:
            fields = {
                "name": None,
                "hot": None,
            }
        self._fields = fields

    def _make(self, fields: dict[str, Any]) -> Tea:
        return Tea(**fields)

效果验证

修改完成后,原有测试用例不需要任何改动即可正常运行,同时返回值类型可以被正确识别:

  • FruitMaker.new().with_(name="Durian").with_(smell="Strong").make() 会被推断为Fruit类型,自动补全name、smell属性
  • TeaMaker.new(name="Camomile", hot=True).make() 会被推断为Tea类型,自动补全name、hot属性

如果你在项目中已经引入了typing_extensions兼容包,可以直接使用其中的Self类型替换我们自定义的M类型变量,写法会更简洁,不需要手动定义自身类型的TypeVar。


内容的提问来源于stack exchange,提问作者André Ricardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 02:06:32