向 mixin 类添加类型注释以使代码通过 mypy 检查的正确方法是什么:
example1.py:
class HostClass:
def host_method(self) -> None:
pass
def overridden_host_method(self) -> None:
pass
class MixinClass:
def mixin_method(self) -> None:
self._other_mixin_method()
self.host_method()
def _other_mixin_method(self) -> None:
pass
def overridden_host_method(self) -> None:
super().overridden_host_method()
class MyClass(MixinClass, HostClass):
pass
obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()
% mypy example1.py
example1.py:11: error: "MixinClass" has no attribute "host_method" [attr-defined]
example1.py:17: error: "overridden_host_method" undefined in superclass [misc]
Found 2 errors in 1 file (checked 1 source file)
mypy 文档中推荐的解决方案(https://mypy.readthedocs.io/en/latest/more_types.html#mixin-classes)以及如何正确地将类型提示添加到 Mixin 类的答案中? 不起作用。
example2.py(HostProtocol 作为“self”的类型注释):
from typing import Protocol
class HostProtocol(Protocol):
def host_method(self) -> None:
...
def overridden_host_method(self) -> None:
...
class HostClass:
def host_method(self) -> None:
pass
def overridden_host_method(self) -> None:
pass
class MixinClass:
def mixin_method(self: HostProtocol) -> None:
self._other_mixin_method()
self.host_method()
def _other_mixin_method(self) -> None:
pass
def overridden_host_method(self) -> None:
super().overridden_host_method()
class MyClass(MixinClass, HostClass):
pass
obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()
% mypy example2.py
example2.py:22: error: "HostProtocol" has no attribute "_other_mixin_method" [attr-defined]
example2.py:29: error: "overridden_host_method" undefined in superclass [misc]
Found 2 errors in 1 file (checked 1 source file)
example3.py(HostProtocol 作为 MixinClass 的基类):
from typing import Protocol
class HostProtocol(Protocol):
def host_method(self) -> None:
...
def overridden_host_method(self) -> None:
...
class HostClass:
def host_method(self) -> None:
pass
def overridden_host_method(self) -> None:
pass
class MixinClass(HostProtocol):
def mixin_method(self) -> None:
self._other_mixin_method()
self.host_method()
def _other_mixin_method(self) -> None:
pass
def overridden_host_method(self) -> None:
super().overridden_host_method()
class MyClass(MixinClass, HostClass):
pass
obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()
% mypy example3.py
example3.py:34: error: Cannot instantiate abstract class "MyClass" with abstract attribute "host_method" [abstract]
example3.py:34: note: "host_method" is implicitly abstract because it has an empty function body. If it is not meant to be abstract, explicitly `return` or `return None`.
Found 1 error in 1 file (checked 1 source file)
example4.py(切换MyClass基类的顺序):
from typing import Protocol
class HostProtocol(Protocol):
def host_method(self) -> None:
...
def overridden_host_method(self) -> None:
...
class HostClass:
def host_method(self) -> None:
pass
def overridden_host_method(self) -> None:
pass
class MixinClass(HostProtocol):
def mixin_method(self) -> None:
self._other_mixin_method()
self.host_method()
def _other_mixin_method(self) -> None:
pass
def overridden_host_method(self) -> None:
print("Mixin overrides")
super().overridden_host_method()
class MyClass(HostClass, MixinClass):
pass
obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()
mypy example4.py
Success: no issues found in 1 source file
但是 overridden_host_method() 不再被重写:
% python example4.py
%
我。 e.不打印“Mixin overrides”。
MixinClass 应:
使用
typing.Protocol
的建议是在最小化运行时和静态类型之间差异的基础上给出的。然而,在大多数情况下,我会避免使用 typing.Protocol
,包括 mixin 类。它们不容易使用,正如您在 example2.py
(如果没有 交叉类型,注释
self
很尴尬)和 example3.py
(基类顺序很难正确,如果可能的话)中发现的那样;这还引入了一个隐藏的元类)。
如果您广泛依赖静态类型并且不介意运行时类型和静态类型之间的差异,那么对于 mixin 类有更好的解决方案。
from __future__ import annotations
import typing_extensions as t
if t.TYPE_CHECKING:
MixinBase: t.TypeAlias = "HostClass"
else:
MixinBase = object
class HostClass:
def host_method(self) -> None: pass
def overridden_host_method(self) -> None: pass
class MixinClass(MixinBase):
def mixin_method(self) -> None:
self._other_mixin_method()
self.host_method() # No Errors
def _other_mixin_method(self) -> None: pass
def overridden_host_method(self) -> None:
super().overridden_host_method() # No Errors
class MyClass(MixinClass, HostClass): pass
>>> obj = MyClass()
>>> obj.mixin_method()
>>> obj.overridden_host_method()