考虑我定义了一个协议Frobbable。此外,我有一个有效的协议实现,以及一个缺少该.frob()方法的损坏的实现:
from typing import Protocol
from abc import abstractmethod
class Frobbable(Protocol):
@abstractmethod
def frob(self) -> None:
raise NotImplementedError
def main(knob: Frobbable) -> None:
knob.frob()
class Knob:
def frob(self) -> None:
print("knob has been frobbed")
class BrokenKnob:
pass
main(Knob())
main(BrokenKnob())
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,使用 mypy 检查该程序会导致错误:
testprotocol.py:25:6: error: Argument 1 to "main" has incompatible type "BrokenKnob"; expected "Frobbable" [arg-type]
main(BrokenKnob())
^
Found 1 error in 1 file (checked 1 source file)
Run Code Online (Sandbox Code Playgroud)
不幸的是,它没有提供任何关于为什么 BrokenKnob不兼容的信息:在这种情况下,它丢失了.frob()。如果没有这样的信息,在一个不平凡的程序(具有许多方法和许多实现的协议)中纠正这样的问题将变得非常乏味的苦差事。
有没有办法在不修改程序的情况下从 mypy 或任何其他工具获取这些信息?我知道我可以显式子类化Frobbable,但这违背了使用Protocol.
我认为这是由于 mypy 用于列出缺失协议成员的启发法的限制。通常情况下,mypy 应该报告任何丢失的协议成员,但为了避免生成太多垃圾邮件错误消息,如果每个协议成员都丢失或者丢失的成员数量超过 2 个,则它不会这样做。
例如,如果我们调整您的示例,使其受到这些限制......
from typing import Protocol
from abc import abstractmethod
class Frobbable(Protocol):
@abstractmethod
def frob(self) -> None:
raise NotImplementedError
@abstractmethod
def bob(self) -> None:
raise NotImplementedError
def main(knob: Frobbable) -> None:
knob.frob()
class BrokenKnob:
def frob(self) -> None:
raise NotImplementedError
main(BrokenKnob())
Run Code Online (Sandbox Code Playgroud)
...我们按照预期得到了更具描述性的错误消息:
test.py:23: error: Argument 1 to "main" has incompatible type "BrokenKnob"; expected "Frobbable"
test.py:23: note: 'BrokenKnob' is missing following 'Frobbable' protocol member:
test.py:23: note: bob
Run Code Online (Sandbox Code Playgroud)
虽然这些启发式方法看起来确实合理,但我也认为它们可能可以进行更多改进,以更好地处理像您遇到的用例这样的用例。例如,如果所有成员都丢失,我认为 mypy 报告“此对象没有实现协议中的任何内容”错误消息而不是更通用的错误消息是合理的,并且也许可以处理以下情况:太多失踪的成员更加优雅。如果您愿意的话,也许可以尝试提交 PR 来改进这些启发式方法?
如果您没有时间,您可以尝试获取完整列表的一种解决方法是:
由此产生的错误似乎列出了所有缺失的属性,而没有固定的限制。
error: Cannot instantiate abstract class 'BrokenKnob' with abstract attribute 'frob'
Run Code Online (Sandbox Code Playgroud)
然后,完成修复后,您可以撤消临时更改。
| 归档时间: |
|
| 查看次数: |
834 次 |
| 最近记录: |