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

如何创建行为与T一致且运行时可区分的Python泛型类型A[T]?

实现行为与T一致但运行时可区分的泛型类型A[T]

方案一:动态继承子类(推荐)

通过动态创建继承自泛型基类和目标类型T的子类,既能让A[T]完全继承T的所有行为,又能在运行时区分实例类型,同时满足类型检查要求。

代码实现:

from typing import Generic, TypeVar, Type, cast
import re

T = TypeVar('T')

class A(Generic[T]):
    # 缓存已创建的子类,避免重复生成
    _cached_subclasses: dict[Type[T], Type['A[T]']] = {}

    def __class_getitem__(cls, item: Type[T]) -> Type[T]:
        # 若对应类型的子类未创建,则动态生成
        if item not in cls._cached_subclasses:
            subclass_name = f"A[{item.__name__}]"
            # 创建继承自A和目标类型item的子类
            subclass = cast(Type[T], type(subclass_name, (cls, item), {}))
            cls._cached_subclasses[item] = subclass
        return cls._cached_subclasses[item]

    def __init__(self, value: T) -> None:
        # 调用目标类型的构造函数完成初始化
        super().__init__(value)

# 测试类型检查与运行时行为
def f(s: A[str]) -> list[str]:
    # mypy会通过检查,因为A[str]被识别为str的子类型
    return re.findall('foo|bar', s)

# 运行时验证
a_str = A[str]("foobar")
print(isinstance(a_str, str))    # 输出: True,行为与str一致
print(isinstance(a_str, A))      # 输出: True,属于A的实例
print(type(a_str))               # 输出: <class '__main__.A[str]'>,与原生str类型区分
print(type(a_str) is str)        # 输出: False,确认类型不同

优缺点

  • 优点:完全继承T的所有方法和属性,无需手动代理;类型检查自动兼容T的场景;运行时清晰区分实例类型。
  • 缺点:仅适用于可被继承的类型(绝大多数Python内置类型和自定义类都支持);动态生成子类需注意缓存避免重复开销。

方案二:包装器代理方案

通过包装T的实例,手动代理所有属性和方法,模拟T的行为,同时保留A的类型标识。

代码实现:

from typing import Generic, TypeVar, Any, cast
import re

T = TypeVar('T')

class A(Generic[T]):
    def __init__(self, value: T) -> None:
        self._inner_value = value

    # 代理所有非特殊方法/属性到内部实例
    def __getattr__(self, name: str) -> Any:
        return getattr(self._inner_value, name)

    # 实现特殊方法以兼容T的核心行为(按需添加)
    def __str__(self) -> str:
        return str(self._inner_value)
    
    def __repr__(self) -> str:
        return f"A({repr(self._inner_value)})"
    
    def __len__(self) -> int:
        return len(self._inner_value)
    
    def __getitem__(self, key: Any) -> Any:
        return self._inner_value[key]
    
    def __eq__(self, other: Any) -> bool:
        if isinstance(other, A):
            return self._inner_value == other._inner_value
        return self._inner_value == other

# 测试类型检查与运行时行为
def f(s: A[str]) -> list[str]:
    # 使用cast告知mypy s可被当作str处理
    return re.findall('foo|bar', cast(str, s))

# 运行时验证
a_str = A[str]("foobar")
print(isinstance(a_str, A))      # 输出: True,属于A的实例
print(isinstance(a_str, str))    # 输出: False,但行为与str一致
print(str(a_str))                # 输出: foobar
print(a_str.upper())             # 输出: FOOBAR(代理str的upper方法)

优缺点

  • 优点:适用于所有类型,包括不可继承的类型;实现更灵活,可自定义代理逻辑。
  • 缺点:需手动实现大量特殊方法(如__add__、__mul__等)才能完全模拟T的行为;类型检查时需手动用cast兼容T的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 02:15:01