Mypy允许我们编写class stubs,可以将其放置在与实际类相同的目录中。此存根与其他语言中的接口非常相似。客户端可以使用存根,并且实现严格遵循存根吗?
我想工作的示例:
class IDependency:
def do_something(self) -> None: ...
def do_something_else(self) -> None: ...
class Service:
def __init__(self, dependency: IDependency):
dependency.do_something()
dependency.do_something_else() # this fails silently
class DependencyImplementation(IDependency):
def do_something(self) -> None:
print("doing something")
# Note there is no `do_something_else` here.
这有效。但是,如果DependencyImplementation
未实现do_something
方法,则Mypy不会出错,Python本身也不会出错。该呼叫只是不执行任何操作。我是否必须编写raise NotImplementedException()
或用@abc.abstractmethod
注释每个方法才能起作用? Mypy或Python解释器中是否有一些特殊标志?
这是Mypy Protocols的用例吗?它似乎即将到来(也许是Python 4?)
答案 0 :(得分:1)
这确实可以使用@abc.abstractmethod
或协议来完成。前者类似于使用Java的抽象类。后者将类似于使用Go的界面或Rust特征。
以下是使用ABC的示例:
from abc import abstractmethod
class Parent:
@abstractmethod
def foo(self) -> None: ...
# Missing an implementation for 'foo'!
class Child(Parent): pass
print(Child()) # Error: Cannot instantiate abstract class 'Child' with abstract attribute 'foo'
关于此示例的一些注意事项:
foo
的用例。abc
元类添加到Parent(例如class Parent(metaclass=ABCMeta)
):mypy会理解@abc.abstractmethod
在有或没有它的含义。仅当您希望Python解释器也强制您正确重写了在运行时标记为抽象的所有内容时,才包含元类。您也可以使用协议,尽管现在您需要先pip install typing_extensions
才能使用它。这是一个示例:
from typing_extensions import Protocol
class CanFoo(Protocol):
def foo(self) -> None: ...
class Child: pass
def expects_fooable(x: CanFoo) -> None: ...
x = Child()
expects_fooable(x) # Error: Argument 1 to "expects_fooable" has incompatible type "Child"; expected "CanFoo"
一些注意事项:
Child
有意不继承自CanFoo
:类与它实现的协议之间没有明确的链接:协议与Go风格的接口非常相似,可以更特别。将此与Java之类的语言进行对比,您确实需要在类定义中包括“ implements Blah”。Child
的实例化上没有得到错误:它本质上没有错。相反,当我们尝试不正确使用它时,我们会得到一个例外。最后几点注意事项: