我有两个基类Foo
和Bar
,还有一个Worker
类,它期望对象的行为类似于Foo
。然后,我添加了另一个类,该类实现了Foo
中的所有相关属性和方法,但是我没有设法通过mypy将其成功传递给静态类型检查。这是一个小例子:
class MyMeta(type):
pass
class Bar(metaclass=MyMeta):
def bar(self):
pass
class Foo:
def __init__(self, x: int):
self.x = x
def foo(self):
pass
class Worker:
def __init__(self, obj: Foo):
self.x = obj.x
此处Worker
实际上接受任何Foo
类对象,即具有属性x
和方法foo
的对象。因此,如果obj
走路像Foo
,并且发出嘎嘎声,则Foo
会很高兴。现在,整个项目都使用类型提示,因此目前我指示Worker
。到目前为止一切顺利。
[现在还有另一个类obj: Foo
,它继承了FooBar
的行为类似于Bar
,但是它不能成为Foo
的子类,因为它通过属性公开了其属性(因此Foo
参数没有意义) ):
__init__
此时,class FooBar(Bar):
"""Objects of this type are bar and they are foo-ish."""
@property
def x(self) -> int:
return 0
def foo(self):
pass
显然会导致类型检查器错误:
Worker(FooBar())
为了将error: Argument 1 to "Worker" has incompatible type "FooBar"; expected "Foo"
-ish的接口传达给类型检查器,我想到了为Foo
-ish类型创建抽象基类:
Foo
但是我无法使import abc
class Fooish(abc.ABC):
x : int
@abc.abstractmethod
def foo(self) -> int:
raise NotImplementedError
继承自FooBar
,因为Fooish
有其自己的元类,因此这会引起元类冲突。因此,我考虑过在Bar
和Fooish.register
上同时使用Foo
,但是mypy并不同意:
FooBar
哪个会产生以下错误:
@Fooish.register
class Foo:
...
@Fooish.register
class FooBar(Bar):
...
class Worker:
def __init__(self, obj: Fooish):
self.x = obj.x
我考虑的下一个选项是创建一个接口,而不以“常规”类的形式从error: Argument 1 to "Worker" has incompatible type "Foo"; expected "Fooish"
error: Argument 1 to "Worker" has incompatible type "FooBar"; expected "Fooish"
继承,然后使abc.ABC
和Foo
都继承自该接口:
FooBar
现在mypy并没有抱怨class Fooish:
x : int
def foo(self) -> int:
raise NotImplementedError
class Foo(Fooish):
...
class FooBar(Bar, Fooish):
...
class Worker:
def __init__(self, obj: Fooish):
self.x = obj.x
的参数类型,而是抱怨Worker.__init__
(它是FooBar.x
)与property
的签名不兼容:
Fooish.x
而且error: Signature of "x" incompatible with supertype "Fooish"
(抽象)基类现在可以实例化,并且是Fooish
的有效参数,尽管它没有意义,因为它不提供属性Worker(...)
。
现在,我陷入了一个问题,即如何在不使用继承的情况下将该接口与类型检查器进行通信(由于元类冲突;即使有可能,mypy仍会抱怨x
的签名不兼容)。有办法吗?
据我所知,您可能可以添加一个x
,基本上可以允许Union
:
Foo or Bar or Fooish