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

如何在Python中创建保留泛型类型信息的工厂函数?

如何在Python中创建保留泛型类型信息的工厂函数?

嘿,我太懂你遇到的这个糟心事了!你想通过工厂函数把EventBus绑定到Property类里,省得每次实例化都要传,但现在类型检查器把返回的类全推断成Property[Any],完全丢了泛型T的类型提示,对吧?

其实这个问题的核心是:你在函数内部动态创建的泛型类,到了函数外面,类型检查器没办法追踪到它原本的泛型参数T,所以只能默认给它标上Any。咱们可以通过两个简单的调整来解决这个问题:

方法一:给工厂函数加明确的泛型返回类型注解+类型转换

直接给create_property函数的返回值加上泛型类型提示,再用cast给类型检查器递个“悄悄话”,告诉它这个类的真实泛型身份,代码调整后是这样的:

from typing import TypeVar, Generic, Callable, Any, Type, cast

T = TypeVar('T')

def create_property(event_bus: EventBus) -> Type[Generic[T]]:
    class Property(Generic[T]):
        def __init__(self, validator: Callable[[T], bool]):
            self._validator = validator

        def __set_name__(self, obj: Any, name: str):
            self.name = name

        def __get__(self, obj: Any, type: Any) -> T:
            return obj.__dict__.get(self.name)

        def __set__(self, obj: Any, value: T):
            if not self._validator(value):
                raise ValueError("Invalid value")
            obj.__dict__[self.name] = value
            event_bus.publish()

    # 告诉类型检查器:这个Property是带泛型T的,不是Any!
    return cast(Type[Generic[T]], Property)

方法二:用预定义泛型基类继承

如果你觉得cast有点“取巧”,也可以先定义一个泛型基类,把通用逻辑都放进去,让动态创建的Property继承它,这样类型检查器就能顺着基类轻松追踪到泛型参数:

from typing import TypeVar, Generic, Callable, Any, Type

T = TypeVar('T')

# 先搞一个泛型基类,把通用的属性逻辑都封装在这里
class PropertyBase(Generic[T]):
    def __init__(self, validator: Callable[[T], bool]):
        self._validator = validator

    def __set_name__(self, obj: Any, name: str):
        self.name = name

    def __get__(self, obj: Any, type: Any) -> T:
        return obj.__dict__.get(self.name)

    def __set__(self, obj: Any, value: T):
        if not self._validator(value):
            raise ValueError("Invalid value")
        obj.__dict__[self.name] = value

def create_property(event_bus: EventBus) -> Type[PropertyBase[T]]:
    # 只在子类里加和EventBus绑定的逻辑
    class Property(PropertyBase[T]):
        def __set__(self, obj: Any, value: T):
            super().__set__(obj, value)
            event_bus.publish()

    return Property

测试一下效果

调整完之后,你再用这个工厂函数创建Property类,类型检查器就能正确识别泛型参数了:

class EventBus:
    def publish(self):
        print("Event published!")

# 创建绑定了EventBus的Property类
MyProperty = create_property(EventBus())

class MyClass:
    # 这里会正确推断为MyProperty[int],再也不是Any了!
    number = MyProperty[int](lambda x: isinstance(x, int))
    # 要是你给number传个字符串,类型检查器会直接跳出来报错提示

这样不管是赋值还是取值,类型提示都能正常工作,而且EventBus也已经稳稳绑定到Property类里,不用每次实例化都传,完美解决你的需求~

备注:内容来源于stack exchange,提问作者Adam A

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 14:58:05