带继承的自定义dataclass装饰器:Pyright无法识别基类方法的类型提示问题
问题解决:让Pyright识别动态装饰类的继承方法
问题根源
静态类型检查器(如Pyright)无法追踪types.new_class动态生成类的完整继承链,再加上装饰器的类型标注不够精确,导致Test类丢失了继承自A、B的方法类型信息。
解决方案
放弃动态创建类的方式,改用静态友好的装饰器实现——直接修改原类的继承关系并应用dataclasses.dataclass,同时修正类型标注让检查器能正确识别继承链。
修改后的代码
from __future__ import annotations import dataclasses import typing as t _Self = t.TypeVar("_Self", bound="A") class A: """Base class for all classes""" @classmethod def create(cls: type[_Self], *args, **kwargs) -> _Self: return cls(*args, **kwargs) def do_something(self) -> None: """a 'void' method""" pass class B(A): """A secondary base class for the future dataclasses; NOTE: inheritance from A!""" T = t.TypeVar("T", bound=B) def decorator(**kwargs) -> t.Callable[[type[T]], type[T]]: """A decorator for reducing boilerplate""" def _decorator(cls: type[T]) -> type[T]: # 让原类继承自B,保留原有基类(如果有的话) cls.__bases__ = (B,) + cls.__bases__ # 应用dataclass装饰器,合并默认参数与传入参数 return dataclasses.dataclass(**{"frozen": True, "kw_only": True, **kwargs})(cls) return _decorator @decorator(repr=False) class Test: """This is an implementation of the dataclass, subclassed from B, subclassed from A""" name: str def __repr__(self) -> str: return self.name def do_something_else(self) -> None: self.do_something() # Pyright现在能正常识别该方法
关键改动说明
- 替换动态类创建逻辑:不再用
types.new_class生成新类,而是直接修改原类的__bases__属性让它继承B,静态检查器能直接追踪到这一继承关系。 - 精确类型标注:装饰器使用泛型
type[T]捕获原类的类型,确保返回的类既保留原类的自定义属性/方法,又能正确体现继承自B、A的类型信息。 - 合并dataclass参数:将默认的
frozen=True、kw_only=True与用户传入的参数合并,保持原有简化样板的需求。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

