在超类中使用Python * args重载类型

时间:2019-05-28 21:40:26

标签: python typing mypy

我有一个简单的基类,如下:

class Base:
  def get(self, *names: str) -> Any:
    # implementation not important

在某些用例中,我试图定义一个具有更严格类型的子类:

from typing import overload, Any
from typing_extensions import Literal

class Sub(Base):
  # mypy error here: Signature of "get" incompatible with supertype "Base"
  @overload
  def get(self, *names: Literal['Something']) -> Something: ...
  @overload
  def get(self, *names: Literal['Else']) -> Else: ...
  def get(self, *names: str) -> Any:
    return super().get(*names)

但是,我得到上面的代码Signature of "get" incompatible with supertype "Base"中指出的错误。我为Sub类的重载参数尝试了其他形式,但是所有形式都会产生类似的错误。

对于采用*args的基类方法,无论如何,传入字面值时在子类中提供特定的重载吗?

1 个答案:

答案 0 :(得分:0)

Sub的正确键入应如下所示:

class Sub(Base):
  @overload
  def get(self, __name: Literal['Something']) -> Something: ...
  @overload
  def get(self, __name: Literal['Else']) -> Else: ...
  @overload
  def get(self, *names: str) -> Any: ...
  def get(self, *names: str) -> Any:
    return super().get(*names)

与问题相比,这里有一些更改。

1)我们定义了一个额外的重载,其类型与实现相同。 python docs for @overload对此进行了解释:“ [non- @ overload-decorated定义]在运行时使用,但应由类型检查器忽略。”

2)没有人会多次传递相同的文字,因此我们最好将*names更改为__name。前导下划线表示name是“仅限位置”的,如in the mypy docs所述:

# An argument can be declared positional-only by giving it a name
# starting with two underscores:
def quux(__x: int) -> None:
    pass

quux(3)  # Fine
quux(__x=3)  # Error

进行了上述更改后,可以根据需要对Sub类进行类型检查。