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

带继承的自定义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现在能正常识别该方法

关键改动说明

  1. 替换动态类创建逻辑:不再用types.new_class生成新类,而是直接修改原类的__bases__属性让它继承B,静态检查器能直接追踪到这一继承关系。
  2. 精确类型标注:装饰器使用泛型type[T]捕获原类的类型,确保返回的类既保留原类的自定义属性/方法,又能正确体现继承自B、A的类型信息。
  3. 合并dataclass参数:将默认的frozen=True、kw_only=True与用户传入的参数合并,保持原有简化样板的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 20:25:33