向 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”的类型注释):
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:
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)
example4.py(切换 MyClass 基类的顺序):| ||但是 overridden_host_method() 不再被重写:
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)
i。 e.不打印“Mixin overrides”。
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
MixinClass 应:
% python example4.py
%
从 HostClass 调用方法
也从自身调用方法
- 覆盖 HostClass 的方法
- call also a method from itself
- override a method of the HostClass
你遇到的问题是,mixin 期望存在于它扩展的类中的一些属性或方法,但在 mixin 本身被定义时,这些属性或方法是不可用的。你有几种方法可以解决这个问题。
1. 使用协议和类型注释
这是 mypy 文档推荐的方法,并且在你的情况下也能工作。 你在
example2.py
和
example3.py
中几乎做对了,但你需要组合这两种方法。
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:
print("HostClass.host_method()")
def overridden_host_method(self) -> None:
print("HostClass.overridden_host_method()")
class MixinClass(HostProtocol):
def mixin_method(self) -> None:
self._other_mixin_method()
self.host_method()
def _other_mixin_method(self) -> None:
print("MixinClass._other_mixin_method()")
def overridden_host_method(self) -> None:
print("MixinClass.overridden_host_method()")
super().overridden_host_method()
class MyClass(HostClass, MixinClass):
pass
obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()
在这个例子中,我们定义了一个
HostProtocol
协议,它描述了
MixinClass
所期望的方法。然后,我们让
MixinClass
继承
HostProtocol
。这告诉 mypy,
MixinClass
可以在任何实现了
HostProtocol
的类中使用。
2. 使用 @runtime_checkable 装饰器
你可以使用
typing.runtime_checkable
装饰器将协议标记为可在运行时检查。这允许你在运行时检查对象是否符合协议,即使它没有在类型提示中声明。
from typing import Protocol, runtime_checkable
@runtime_checkable
class HostProtocol(Protocol):
def host_method(self) -> None:
...
def overridden_host_method(self) -> None:
...
# ... rest of the code is the same as in the previous example
这种方法的优点是,你不需要改变
HostClass
的定义,即使它没有明确继承
HostProtocol
,mypy 也会识别它。
3. 明确地将 mixin 应用到类
如果你不想使用协议,你可以明确地将 mixin 应用到类。 这意味着将 mixin 类作为参数传递给类定义,并在类定义中调用 mixin 类的方法。
class HostClass:
def host_method(self) -> None:
print("HostClass.host_method()")
def overridden_host_method(self) -> None:
print("HostClass.overridden_host_method()")
class MixinClass:
def mixin_method(self) -> None:
self._other_mixin_method()
self.host_method()
def _other_mixin_method(self) -> None:
print("MixinClass._other_mixin_method()")
def overridden_host_method(self) -> None:
print("MixinClass.overridden_host_method()")
super().overridden_host_method()
class MyClass(HostClass):
def __init__(self) -> None:
super().__init__()
MixinClass().mixin_method(self)
MixinClass().overridden_host_method(self)
obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()
这种方法的优点是不需要使用协议,但是它需要更改你的类的定义,并且可能比使用协议更复杂。
选择哪种方法取决于你的具体需求和编码风格。 如果你想要最灵活和可扩展的解决方案,那么使用协议是最好的方法。 如果你想要一个更简单的解决方案,并且你不介意更改类的定义,那么明确地将 mixin 应用到类可能更适合你。
标签:python,python-typing,mypy,mixins From: 77283935