mypy 使用子方法的名称而不是父方法的通用签名来更新子方法的返回值

问题描述 投票:0回答:1

我有一个

Generic
基类,它以一种方法返回自身 (
get_self
)。 我已经键入了这样的暗示。

然后我有一个该基类的子类,它传入

Generic
的类型参数。 在那个孩子班里,我叫
get_self
。我想将类型提示更新为子类的名称。

但是,

mypy==0.782
正在报告
error: Incompatible return value type (got "Foo[Bar]", expected "DFoo")  [return-value]
。 有什么办法可以做到这一点吗?


**编辑**

经过进一步思考,我决定重新解释这个问题。 提前抱歉啰嗦了。

  1. 基类 (
    Foo
    ) 有一个方法 (
    get_self
    ) 类型暗示返回其自身的实例
  2. 子类(
    DFoo
    )不会重写该方法
  3. Child 类然后使用 (
    get_self
    ) 方法
    • 并且知道返回类型实际上是子类的(
      DFoo
      )
  4. 但是,静态类型检查器(例如:
    mypy
    )不知道子类的方法实际上会返回子类的对象,因为它们正在使用基类的类型提示

因此,如果不在子类中使用新类型提示重新声明方法(

get_self
),我的问题可能无法实现。

我可以使

get_self
的返回成为
TypeVar
。 但是,由于基类
Foo
已经是
Generic
,目前这是不可能的,因为它需要 python/typing Higher-Kinded TypeVars #548 中提到的“Higher-Kinded TypeVars”。


示例脚本

我希望这能澄清我想要表达的意思。

from __future__ import annotations

from typing import Generic, TypeVar, cast

T = TypeVar("T")

class Foo(Generic[T]):
    def get_self(self) -> Foo[T]:
        # Other stuff happens here before the return
        return self

class Bar:
    pass

class DFoo(Foo[Bar]):
    def do_something_get_self(self) -> DFoo:
        # mypy error: Incompatible return value type (got "Foo[Bar]", 
        # expected "DFoo")
        return self.get_self()

class DFooCast(Foo[Bar]):
    def do_something_get_self(self) -> DFooCast:
        # This works, but I don't like this method. I don't want to use `cast`
        # all over the place.
        return cast(DFooCast, self.get_self())

class DFooNoUpdatedTypeHint(Foo[Bar]):
    def do_something_get_self(self) -> Foo[Bar]:
        # mypy doesn't error here, but later on it will raise an error 
        # when using method's added in Foo subclasses
        return self.get_self()

    def dfoo_adds_method(self) -> None:
        """DFoo also has additional methods."""

dfoo = DFooNoUpdatedTypeHint()
dfoo.do_something_get_self().dfoo_adds_method()  # error: "Foo[Bar]" has no attribute "dfoo_adds_method"

这是完整的 mypy 输出:

path/to/ret_type_type_t_subclass.py: note: In member "do_something_get_self" of class "DFoo":
path/to/ret_type_type_t_subclass.py: error: Incompatible return value type (got "Foo[Bar]", expected "DFoo")  [return-value]
path/to/ret_type_type_t_subclass.py: note: At top level:
path/to/ret_type_type_t_subclass.py: error: "Foo[Bar]" has no attribute "dfoo_adds_method"  [attr-defined]

版本

Python==3.8.5
mypy==0.782
python python-typing mypy
1个回答
2
投票

要解决此问题,只需将

get_self
函数键入为
def get_self(self: S) -> S
,其中 S 是某种类型 var。

以下程序将干净地键入检查:

from __future__ import annotations

from typing import Generic, TypeVar, cast

T = TypeVar("T")

# This can also be just 'S = TypeVar("S")', but that would mean
# we won't be able to use any methods of Foo inside of get_self.
S = TypeVar("S", bound="Foo")


class Foo(Generic[T]):
    def get_self(self: S) -> S:
        return self

class Bar:
    pass


class DFoo(Foo[Bar]):
    def do_something_get_self(self) -> DFoo:
        return self.get_self()

    def dfoo_adds_method(self) -> None:
        pass


dfoo = DFoo()
dfoo.do_something_get_self().dfoo_adds_method()

它起作用的原因是因为它总是可以覆盖

self
的默认类型。虽然它通常会自动给出当前类的类型,但 PEP 484 实际上并不要求您坚持使用此默认值。

因此,我们将其设为通用,以确保输出类型始终与当前子类型匹配。

有关此交互的更多详细信息,请参阅 https://mypy.readthedocs.io/en/stable/generics.html#generic-methods-and-generic-self

© www.soinside.com 2019 - 2024. All rights reserved.