使用元类应用attrs.frozen后Python类型注解失效,如何适配类型检查器?
让类型检查器识别元类自动应用attrs.frozen的效果
类型检查器(如VSCode默认的Pyright)不会执行元类的运行时代码,只会静态分析类定义,所以直接用元类生成的frozen类无法被识别为attrs装饰后的结构。以下是几种可行的解决方法:
方案一:通过泛型类型变量引导类型推断
利用typing.TypeVar和Generic让元类生成的类具备与@frozen装饰类一致的类型行为:
from typing import TypeVar, Generic, TYPE_CHECKING, Any import attrs T = TypeVar('T') class MetaKlass(type, Generic[T]): def __new__(mcs, name: str, bases: tuple[type, ...], attrs: dict[str, Any]): new = super().__new__(mcs, name, bases, attrs) if TYPE_CHECKING or '__attrs_attrs__' not in attrs: return attrs.frozen(new) return new def __class_getitem__(cls, item): return cls class Klass(metaclass=MetaKlass): attribute: int
泛型标记会让类型检查器将该类视为attrs风格的数据类,从而正确解析属性的类型提示。
方案二:类型检查阶段模拟frozen类继承
在TYPE_CHECKING模式下,让目标类直接继承一个预定义的frozen基类,给类型检查器提供明确的结构提示:
import attrs from typing import TYPE_CHECKING, Any, type # 类型检查时让类继承自attrs.frozen装饰的空类 if TYPE_CHECKING: BaseFrozen = attrs.frozen(type('BaseFrozen', (), {})) else: BaseFrozen = object class MetaKlass(type): def __new__(mcs, name: str, bases: tuple[type, ...], attrs: dict[str, Any]): new = super().__new__(mcs, name, bases, attrs) if '__attrs_attrs__' not in attrs: return attrs.frozen(new) return new class Klass(BaseFrozen, metaclass=MetaKlass): attribute: int
这种方式通过静态继承关系,让类型检查器直接识别类的frozen属性和结构。
方案三:添加类型检查器识别的attrs标记
给类添加__attrs_frozen__和__attrs_attrs__的静态注解,直接告诉类型检查器这是一个frozen的attrs类:
import attrs from typing import TYPE_CHECKING, Any class MetaKlass(type): def __new__(mcs, name: str, bases: tuple[type, ...], attrs: dict[str, Any]): new = super().__new__(mcs, name, bases, attrs) if TYPE_CHECKING or '__attrs_attrs__' not in attrs: frozen_cls = attrs.frozen(new) return frozen_cls return new class Klass(metaclass=MetaKlass): attribute: int # 给类型检查器的静态标记 __attrs_frozen__: bool = True __attrs_attrs__: list[attrs.Attribute] = []
Pyright、Mypy等类型检查器会通过这些标记识别类的attrs特性,从而显示正确的初始化参数和属性类型提示。
内容的提问来源于stack exchange,提问作者Daniel Konopka
相关产品推荐
相关产品推荐

