如果 mixin 的目标 class 继承自 metaclass,如何键入提示 mixins?
How to typehint mixins if the target class for the mixin inherits from a metaclass?
考虑以下 class 和 mixin:
class Target(ClassThatUsesAMetaclass):
def foo(self):
pass
class Mixin:
def __init__(self):
self.foo() # type error: type checker doesn't know Mixin will have
# access to foo once in use.
class Combined(Mixin, Target):
def __init__(self):
Target.__init__(self)
Mixin.__init__(self)
我试图避免上述情况中的类型检查器错误。一种选择是:
from typing import Protocol
class Fooable(Protocol):
def foo(self): ...
class Mixin(Fooable):
def __init__(self):
self.foo()
会很好用,除了 Target
继承自使用元 class 的 class,因此 Combined
不能同时继承两个 Target
和 Mixin
。
所以现在我正在尝试另一种方法,在 Mixin
:
中注释 self
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .this import Mixin, Target
Mixin_T = type('Mixin_T', (Mixin, Target), {})
class Mixin:
def __init__(self: Mixin_T):
self.foo() # No longer an error
class Combined(Mixin, Target):
def __init__(self):
Target.__init__(self)
Mixin.__init__(self) # Now this is an error: "Type[Mixin]" is not
# assignable to parameter "self"
# "Mixin" is incompatible with "Mixin_T"
除了使用 # type: ignore
之外,我应该如何赢得这场比赛?
除此之外,除了提供一些说明外,上面几乎没有代码和一些错误概念使这个问题根本无法回答。
首先,您确定您“继承自元class”吗??除非创建另一个元class,否则继承元class没有意义。你的片段显示你从一个假设的元class(没有给出代码)中继承,创建Target
并且他们试图使用Target
作为普通class(a非元 class)。这毫无意义。
您可能只是混淆了术语,隐藏的 InheritFromMetaclass
class 实际上只是使用元 class,而不是从它“继承”。那么你的问题根本就与 metaclasses 无关。
因此,代码段中真正可见的问题是静态检查器没有“看到”Mixin class 中的 self.foo
方法 - 你猜怎么着?在 Mixin
中没有 self.foo
方法 - 检查器只是在你脸上抛出一个冷酷的事实:而 Python 会 允许 引用在 class 中不可用的方法和属性,知道它将与其他 class 确实具有这些属性的方法和属性一起使用,这不是好的设计和容易出错。那种糟糕的设计静态类型检查存在被淘汰。
所以,您需要的是 Mixin
的基础,它是一个抽象的 class,并且 Foo
作为一个抽象方法。 (或者 Mixin
本身就是抽象的 class)。
如果 - 由于使用了其他元class,由于元class冲突,您无法让 Mixin 从 abc.ABC
继承,您必须:创建一个组合元class 来自 InheritsFromMetaclass
与 ABCMeta
实际使用的 metaclass ,并将其用作 Mixin
的 metaclass - 或者只是创建一个按原样存根 Mixin
中的 foo
方法(它可以引发 NotImplementedError
- 因此具有与抽象方法相同的行为,但实际上不必继承它。
要包含的重要部分是,您在 class 主体中的代码中访问的方法和属性必须存在于 class 中,而不依赖于将存在于主体中的属性它的子class。
如果这不能解决您的问题,您需要提供更多数据 - 包括涉及您的实际元的可重现的完整示例class。 (并且它可以通过组合上面提到的 metaclasses 来解决)
我找到了一个非常简单的解决方案:
if TYPE_CHECKING:
from .this import Target
Mixin_T = Target
else:
Mixin_T = object
class Mixin(Mixin_T):
...
现在 Target
的所有方法都在 Mixin
中被类型检查器识别,并且不需要将 self
的类型覆盖为与 [=12] 不兼容的类型=].如果 mixin 注定要用于各种 Target
classes,这可能会有点尴尬,但对于我的使用来说,这是完全可以接受的,因为我的情况是一组 mixins 扩展了一个非常具体的目标 class.
考虑以下 class 和 mixin:
class Target(ClassThatUsesAMetaclass):
def foo(self):
pass
class Mixin:
def __init__(self):
self.foo() # type error: type checker doesn't know Mixin will have
# access to foo once in use.
class Combined(Mixin, Target):
def __init__(self):
Target.__init__(self)
Mixin.__init__(self)
我试图避免上述情况中的类型检查器错误。一种选择是:
from typing import Protocol
class Fooable(Protocol):
def foo(self): ...
class Mixin(Fooable):
def __init__(self):
self.foo()
会很好用,除了 Target
继承自使用元 class 的 class,因此 Combined
不能同时继承两个 Target
和 Mixin
。
所以现在我正在尝试另一种方法,在 Mixin
:
self
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .this import Mixin, Target
Mixin_T = type('Mixin_T', (Mixin, Target), {})
class Mixin:
def __init__(self: Mixin_T):
self.foo() # No longer an error
class Combined(Mixin, Target):
def __init__(self):
Target.__init__(self)
Mixin.__init__(self) # Now this is an error: "Type[Mixin]" is not
# assignable to parameter "self"
# "Mixin" is incompatible with "Mixin_T"
除了使用 # type: ignore
之外,我应该如何赢得这场比赛?
除此之外,除了提供一些说明外,上面几乎没有代码和一些错误概念使这个问题根本无法回答。
首先,您确定您“继承自元class”吗??除非创建另一个元class,否则继承元class没有意义。你的片段显示你从一个假设的元class(没有给出代码)中继承,创建Target
并且他们试图使用Target
作为普通class(a非元 class)。这毫无意义。
您可能只是混淆了术语,隐藏的 InheritFromMetaclass
class 实际上只是使用元 class,而不是从它“继承”。那么你的问题根本就与 metaclasses 无关。
因此,代码段中真正可见的问题是静态检查器没有“看到”Mixin class 中的 self.foo
方法 - 你猜怎么着?在 Mixin
中没有 self.foo
方法 - 检查器只是在你脸上抛出一个冷酷的事实:而 Python 会 允许 引用在 class 中不可用的方法和属性,知道它将与其他 class 确实具有这些属性的方法和属性一起使用,这不是好的设计和容易出错。那种糟糕的设计静态类型检查存在被淘汰。
所以,您需要的是 Mixin
的基础,它是一个抽象的 class,并且 Foo
作为一个抽象方法。 (或者 Mixin
本身就是抽象的 class)。
如果 - 由于使用了其他元class,由于元class冲突,您无法让 Mixin 从 abc.ABC
继承,您必须:创建一个组合元class 来自 InheritsFromMetaclass
与 ABCMeta
实际使用的 metaclass ,并将其用作 Mixin
的 metaclass - 或者只是创建一个按原样存根 Mixin
中的 foo
方法(它可以引发 NotImplementedError
- 因此具有与抽象方法相同的行为,但实际上不必继承它。
要包含的重要部分是,您在 class 主体中的代码中访问的方法和属性必须存在于 class 中,而不依赖于将存在于主体中的属性它的子class。
如果这不能解决您的问题,您需要提供更多数据 - 包括涉及您的实际元的可重现的完整示例class。 (并且它可以通过组合上面提到的 metaclasses 来解决)
我找到了一个非常简单的解决方案:
if TYPE_CHECKING:
from .this import Target
Mixin_T = Target
else:
Mixin_T = object
class Mixin(Mixin_T):
...
现在 Target
的所有方法都在 Mixin
中被类型检查器识别,并且不需要将 self
的类型覆盖为与 [=12] 不兼容的类型=].如果 mixin 注定要用于各种 Target
classes,这可能会有点尴尬,但对于我的使用来说,这是完全可以接受的,因为我的情况是一组 mixins 扩展了一个非常具体的目标 class.