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

如何让mypy识别自定义类装饰器的代码转换?

让Mypy识别自定义类装饰器的方法

Mypy无法自动推断自定义装饰器对类的修改行为,需要通过类型提示或专用装饰器明确告知Mypy装饰器的作用,以下是几种可行方案:

方案一:使用dataclass_transform装饰器(推荐)

从Python 3.11开始,typing模块提供了dataclass_transform装饰器,专门用来告诉Mypy你的装饰器会像@dataclass一样修改类结构(比如添加__init__方法和类属性)。修改后的代码如下:

import dataclasses
from typing import dataclass_transform

@dataclass_transform()
def my_decorator(cls):
    def init(self, x: int):
        self.x = x

    setattr(cls, '__init__', init)
    return cls

@my_decorator
class Bar:
    pass

bar = Bar(2)
print(bar.x)  # Mypy不再报错

如果你的Python版本低于3.11,可以从typing_extensions库导入dataclass_transform。这个装饰器会让Mypy自动识别装饰器为类添加的构造方法和属性。

方案二:用Protocol+TypeVar显式声明类型

如果需要更精细的类型控制,可以通过Protocol定义装饰后类的结构,结合TypeVar保留原类的类型信息:

from typing import TypeVar, Protocol, Generic

class HasX(Protocol):
    x: int

T = TypeVar('T')

def my_decorator(cls: type[T]) -> type[T & HasX]:
    def init(self, x: int):
        self.x = x

    setattr(cls, '__init__', init)
    return cls

@my_decorator
class Bar:
    pass

bar = Bar(2)
print(bar.x)

这种方式明确告诉Mypy,被装饰后的类既保留原类的特性,又实现了HasX协议(拥有x属性),从而消除类型报错。

方案三:添加类型注释占位符

最简单的临时解决办法是在被装饰的类中新增属性的类型注释(无需实际赋值),让Mypy提前知晓该属性的存在:

def my_decorator(cls):
    def init(self, x: int):
        self.x = x

    setattr(cls, '__init__', init)
    return cls

@my_decorator
class Bar:
    x: int  # 仅添加类型注释,无需初始化

bar = Bar(2)
print(bar.x)

这种方法需要手动维护类中的注释,适合简单场景,灵活性不如前两种方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 13:52:34