Python 泛型和子类

bru*_*nns 6 python generics mypy

我正在尝试向现有包添加类型注释,显然我错过了一些重要的东西。我有一个抽象的超类和子类。超类应该是通用的,而子类应该是针对特定类型的。这是我看到的一个简单示例,以及我希望看到的内容:

from typing import Generic, TypeVar

T = TypeVar("T")

class A(Generic[T]):
    def method(self, arg: T):
        ...

class B(A[int]):
    def method(self, arg):
        reveal_locals()
Run Code Online (Sandbox Code Playgroud)

预期(或至少希望):

GenericTest.py:11: note: Revealed local types are:
GenericTest.py:11: note:     arg: int
GenericTest.py:11: note:     self: Any
Run Code Online (Sandbox Code Playgroud)

得到了:

GenericTest.py:11: note: Revealed local types are:
GenericTest.py:11: note:     arg: Any
GenericTest.py:11: note:     self: Any
Run Code Online (Sandbox Code Playgroud)

Vic*_*uiz 6

reveal_locals()打印 mypy 在调用所在范围内推断的变量类型。当在子类中重新定义方法时,您也会覆盖注释(Any当没有显式给出参数注释时默认使用)

这可能更清楚:

class A(Generic[T]):
    def method(self, arg: T):
        ...

class B(A[int]):
    def method(self, arg):
        pass

B().method('')
Run Code Online (Sandbox Code Playgroud)

上面的代码对于 mypy 来说没问题,但是下面的代码给出了错误:

class C(A[int]):
    pass

C().method('')
Run Code Online (Sandbox Code Playgroud)
error: Argument 1 to "method" of "A" has incompatible type "str"; expected "int"
Run Code Online (Sandbox Code Playgroud)


Mic*_*x2a 5

您需要为子类中的方法添加类型注释。这样做:

from typing import Generic, TypeVar

T = TypeVar("T")

class A(Generic[T]):
    def method(self, arg: T) -> None:
        ...

class B(A[int]):
    def method(self, arg: int) -> None:
        reveal_locals()
Run Code Online (Sandbox Code Playgroud)

...导致预期输出:

test.py:11: note: Revealed local types are:
test.py:11: note:     arg: builtins.int
test.py:11: note:     self: test.B
Run Code Online (Sandbox Code Playgroud)

如果一个函数没有用类型提示进行注释,mypy 会将该函数视为动态类型并假定其所有参数都是 type Any

如果您希望 mypy 在您忘记这样的类型提示时向您发出警告,请使用--disallow-untyped-defs命令行标志运行 mypy —— 也可能--disallow-incomplete-defs是一个很好的衡量标准。或者,运行带有--strict标志的mypy ,它会自动启用上述两个标志(以及更多)。

  • 这当然有效,但感觉重复——我在两个地方需要“int”(在现实世界的情况下可能更多)。类“A”是在泛型类型“T”上定义的,我希望能够定义一个子类,将“T”设置为具体类型,仅一次,但我发现这是行不通的。不过还是谢谢你的帮助! (4认同)