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

如何从元类参数推断泛型类型,避免重复指定类型?

解决方案:从泛型基类自动提取被包装类型

你可以通过访问子类的__orig_bases__属性(Python 3.9+支持)提取泛型参数,避免重复指定类型。元类可自动解析泛型基类中的类型参数,替代手动传入的wrapped_class参数。

修改后的元类与代码示例

from typing import TypeVar, Generic, get_args, get_origin

T = TypeVar('T')

class Meta(type):
    def __new__(
        cls,
        name: str,
        bases: tuple[type, ...],
        cls_dict: dict[str, object],
        wrapped_class: type | None = None,
    ):
        # 未手动传入wrapped_class时,从泛型基类提取
        if wrapped_class is None:
            for base in bases:
                origin = get_origin(base)
                if origin is Wrapper:
                    wrapped_class = get_args(base)[0]
                    break
            else:
                raise TypeError("必须指定wrapped_class,或继承自带泛型参数的Wrapper类")
        
        # 原有的方法检查逻辑
        for member in wrapped_class.__dict__:
            if member.startswith("__"):
                continue
            if member not in cls_dict:
                raise TypeError(f"需要实现 {member}")

        return super().__new__(cls, name, bases, cls_dict)

class Base:
    def foo(self):
        return "bar"

class Wrapper(Generic[T], metaclass=Meta):
    def do_wrapper_stuff(self, arg: T) -> T:
        return arg

# 仅需指定泛型参数,无需手动传wrapped_class
class BaseWrapper(Wrapper[Base]):
    def foo(self):
        # 按权限逻辑实现或拦截方法
        raise PermissionError("禁止直接调用foo方法")

关键说明

  • get_origin与get_args:这两个函数用于解析泛型类型,get_origin返回泛型的原始类(如Wrapper),get_args返回泛型参数(如(Base,))。
  • 兼容手动传入:保留wrapped_class参数的可选性,满足特殊场景下的手动指定需求。
  • 类型检查有效:泛型参数Wrapper[Base]会被类型检查器识别,保障代码类型安全。

兼容旧版本的替代方案:工厂函数生成包装类

如果需要兼容Python 3.9以下版本,可通过工厂函数封装类型指定逻辑,让用户仅传入一次类型:

from typing import TypeVar, Generic

T = TypeVar('T')

class Meta(type):
    def __new__(
        cls,
        name: str,
        bases: tuple[type, ...],
        cls_dict: dict[str, object],
        wrapped_class: type,
    ):
        for member in wrapped_class.__dict__:
            if member.startswith("__"):
                continue
            if member not in cls_dict:
                raise TypeError(f"需要实现 {member}")
        return super().__new__(cls, name, bases, cls_dict)

class Base:
    def foo(self):
        return "bar"

class Wrapper(Generic[T], metaclass=Meta):
    def do_wrapper_stuff(self, arg: T) -> T:
        return arg

def create_wrapper_class(wrapped_cls: type, name: str | None = None) -> type:
    name = name or f"{wrapped_cls.__name__}Wrapper"
    # 动态创建子类,自动传递泛型参数和元类参数
    return type(name, (Wrapper[wrapped_cls],), {}, wrapped_class=wrapped_cls)

# 使用工厂函数,仅传入一次Base类型
BaseWrapper = create_wrapper_class(Base)
# 实现要求的方法
BaseWrapper.foo = lambda self: PermissionError("禁止直接调用foo方法")

为什么不继承被包装类?

正如你提到的,继承被包装类会让包装类自动拥有其所有属性和方法,无法通过元类检查强制实现权限控制逻辑。而泛型+元类的方式,既能让类型检查器识别被包装类型,又能在运行时强制包装类显式实现(或拦截)被包装类的方法,完美适配权限系统需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 20:22:32