2

我有以下代码:

class Mixin:
    def foo(self) -> int:
        return 1

def add_mixin(cls):
    class WithMixin(cls, Mixin):
        __name__ = cls.__name__
        __doc__ = cls.__doc__
    return WithMixin

@add_mixin
class B:
    def bar(self) -> int:
        return 2

b = B()
print(b.foo())
print(b.bar())

我明白,在这种特殊情况下,我可以只编写B(Mixin)并避免使用装饰器,但实际上 中有很多逻辑add_mixin,它选择/自定义Mixin类(想想@dataclass)。

代码按您期望的方式工作:打印 1 和 2。但是,它使我蒙蔽了双眼pyright- 我不再可以跳转到bar,因为pyright不明WithMixin白继承自MixinB

此外,mypy以另一种方式感到困惑:

mypy type_checking.py
type_checking.py:17: error: "B" has no attribute "foo"
Found 1 error in 1 file (checked 1 source file)

我正在注释现有库的核心,所以列表@overloads或一些彻底的魔法对我来说很好 - 我只是希望注释是正确的。

我想在两件事上得到一些帮助:

  1. 我如何正确注释add_mixin(或重写它以产生相同的效果)以便pyright/mypy正常工作?
  2. 有没有关于打字的综合资源?最好是解释typing模块的实现(这令人困惑!)以及类型检查器使用这些注释的方式。我已经阅读了有关 typing以及PEP 483PEP 484的参考资料,并且我认为我对所有协变/逆变/绑定类型的东西都有很好的掌握。然而,当有一个我以前从未见过的复杂案例时(比如这里),我感到完全迷失了。谷歌搜索大多会导致相同的参考风格或表面级文章(或 PEP)。

我经历了很多失败的尝试,最后一个是:

from typing import *

class Mixin:
    def foo(self) -> int:
        return 1

_T1 = TypeVar("_T1")
class WithMixin(Type[_T1], Mixin):
    ...


def add_mixin(cls: Type[_T1]) -> WithMixin[_T1]:
    return type(cls.__name__, (cls, Mixin), {})

@add_mixin
class B:
    def bar(self) -> int:
        return 2

b = B()
print(b.foo())
print(b.bar())

pyright在这条线上感到困惑type(cls.__name__, (cls, Mixin), {}),同时mypy说不允许继承Type[_T1](它不是,但我认为类型检查器可能会选择它)。

4

0 回答 0