Mypy 无法识别 class 装饰器
Mypy doesn't recognize class decorator
问题
假设我想实现一个 class 装饰器,为现有的 class 添加一些属性和函数。
特别是,假设我有一个名为 HasNumber
的协议,我需要一个装饰器 can_add
来添加缺少的方法以将 HasNumber
class 转换为 CanAdd
.
class HasNumber(Protocol):
num: int
class CanAdd(HasNumber):
def add(self, num: int) -> int: ...
实施
我实现装饰器如下:
_HasNumberT = TypeVar("_HasNumberT", bound=HasNumber)
def can_add(cls: Type[_HasNumberT]) -> Type[CanAdd]:
def add(self: _HasNumberT, num: int) -> int:
return self.num + num
setattr(cls, "add", add)
return cast(Type[CanAdd], cls)
@can_add
class Foo:
num: int = 12
错误
代码在我 运行 时工作得很好,但 mypy 出于某种原因对此不满意。
它给出错误 "Foo" has no attribute "add" [attr-defined]
,就好像它没有考虑 can_add
装饰器的 return 值(注释为 Type[CanAdd]
)。
foo = Foo()
print(foo.add(4)) # "Foo" has no attribute "add" [attr-defined]
reveal_type(foo) # note: Revealed type is "test.Foo"
问题
在这个issue中,有人演示了一种用Intersection
注释的方法。但是,没有 Intersection
有没有办法实现呢? (假设我不关心 Foo
中的其他属性,除了协议中定义的属性)
或者是mypy本身的限制?
没有解决我问题的相关帖子:
- Class Decorator Compatible for Mypy
cast
告诉 mypy
cls
(有或没有 add
属性)可以安全地用作 [=15] 的 return 值=].它不保证协议成立。
因此,mypy
无法判断 Foo
是否已被赋予 add
属性,只能判断是否可以使用 can_add
装饰器。 can_add
具有定义 add
属性的副作用这一事实对 mypy
.
不可见
但是,您可以用直接继承替换装饰器,例如
class HasNumber(Protocol):
num: int
_HasNumberT = TypeVar("_HasNumberT", bound=HasNumber)
class Adder(HasNumber):
def add(self, num: int) -> int:
return self.num + num
class Foo(Adder):
num: int = 12
foo = Foo()
print(foo.add(4))
问题
假设我想实现一个 class 装饰器,为现有的 class 添加一些属性和函数。
特别是,假设我有一个名为 HasNumber
的协议,我需要一个装饰器 can_add
来添加缺少的方法以将 HasNumber
class 转换为 CanAdd
.
class HasNumber(Protocol):
num: int
class CanAdd(HasNumber):
def add(self, num: int) -> int: ...
实施
我实现装饰器如下:
_HasNumberT = TypeVar("_HasNumberT", bound=HasNumber)
def can_add(cls: Type[_HasNumberT]) -> Type[CanAdd]:
def add(self: _HasNumberT, num: int) -> int:
return self.num + num
setattr(cls, "add", add)
return cast(Type[CanAdd], cls)
@can_add
class Foo:
num: int = 12
错误
代码在我 运行 时工作得很好,但 mypy 出于某种原因对此不满意。
它给出错误 "Foo" has no attribute "add" [attr-defined]
,就好像它没有考虑 can_add
装饰器的 return 值(注释为 Type[CanAdd]
)。
foo = Foo()
print(foo.add(4)) # "Foo" has no attribute "add" [attr-defined]
reveal_type(foo) # note: Revealed type is "test.Foo"
问题
在这个issue中,有人演示了一种用Intersection
注释的方法。但是,没有 Intersection
有没有办法实现呢? (假设我不关心 Foo
中的其他属性,除了协议中定义的属性)
或者是mypy本身的限制?
没有解决我问题的相关帖子:
- Class Decorator Compatible for Mypy
cast
告诉 mypy
cls
(有或没有 add
属性)可以安全地用作 [=15] 的 return 值=].它不保证协议成立。
因此,mypy
无法判断 Foo
是否已被赋予 add
属性,只能判断是否可以使用 can_add
装饰器。 can_add
具有定义 add
属性的副作用这一事实对 mypy
.
但是,您可以用直接继承替换装饰器,例如
class HasNumber(Protocol):
num: int
_HasNumberT = TypeVar("_HasNumberT", bound=HasNumber)
class Adder(HasNumber):
def add(self, num: int) -> int:
return self.num + num
class Foo(Adder):
num: int = 12
foo = Foo()
print(foo.add(4))