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

如何为函数标注两个绑定同一父类的泛型参数?

问题:如何为共享同一基类的两个参数编写有意义的类型提示?

我想要编写一个接收两个参数的函数,这两个参数需兼容同一基类:

def example_function(desired_type: type[DesiredType], base_object: RelatedType) -> DesiredType:
    ...

其中RelatedType和DesiredType应为绑定到同一父类的类型变量(该父类仅在调用函数传入具体参数时确定)。

这类函数的一个典型示例是工厂类方法,它可基于另一个被认为在特定上下文下部分“兼容”的对象的属性,创建同类实例:

class Example:
    @classmethod
    def from_existing(cls: type[SelfType], existing_object: OtherType) -> SelfType:
        ...

SelfType = TypeVar("SelfType", bound=Example)
OtherType = TypeVar("OtherType", bound=Example)

但OtherType在泛型函数签名中仅出现一次,因此会被标记为reportInvalidTypeVarUse错误。此示例中,简单的解决方法是将OtherType替换为Example本身,它自然兼容其子类。

我了解无法强制不同类型变量之间的继承关系,例如:

BaseType = TypeVar("BaseType")
DerivedType = TypeVar("DerivedType", bound=BaseType)

因为泛型类型不能作为上界。请问如何提供有意义的类型提示,以传达这种预期的关系?


解决方案

方法一:单类型变量约束公共基类

直接定义一个绑定到公共基类的类型变量,同时约束两个参数的类型范围,既满足同一基类的关联要求,又避免类型变量单出现的错误:

from typing import TypeVar, Type

Base = TypeVar("Base")

def example_function(desired_type: type[Base], base_object: Base) -> Base:
    # 示例实现:复制属性创建新实例
    return desired_type(**{k: v for k, v in base_object.__dict__.items() if not k.startswith("_")})

调用时,类型检查器会自动推导Base为传入的desired_type和base_object的共同基类,确保二者类型兼容。

方法二:用Protocol定义兼容接口

如果base_object不需要严格属于同一继承体系,只需要具备特定属性或方法,用Protocol定义兼容接口是更灵活的选择:

from typing import TypeVar, Type, Protocol

class HasCoreAttrs(Protocol):
    id: str
    name: str

T = TypeVar("T", bound=HasCoreAttrs)

def example_function(desired_type: type[T], base_object: HasCoreAttrs) -> T:
    # 基于协议属性创建实例
    return desired_type(id=base_object.id, name=base_object.name)

只要base_object实现了HasCoreAttrs协议的属性,无论它属于哪个类体系,都能被函数接受,同时desired_type必须是该协议的子类。

方法三:工厂方法的简化写法(Python 3.11+)

针对你提到的工厂类场景,Python 3.11引入的Self类型可以自动推导子类类型,结合基类约束参数,写法更简洁:

from typing import Self

class Example:
    def __init__(self, value: int):
        self.value = value

    @classmethod
    def from_existing(cls, existing_object: "Example") -> Self:
        return cls(existing_object.value)

Self会自动对应调用from_existing的子类类型,existing_object用基类Example约束,天然兼容所有子类实例,无需额外定义类型变量。


内容的提问来源于stack exchange,提问作者Vexx23

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 13:05:13