为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕田峪9158850 2023-08-22 16:38:35
我有一个Generic基类,它以一种方法返回自身(get_self)。我已经打字暗示了这一点。然后,我有一个该基类的子类,它传入Generic. 在那个儿童班里,我打电话给get_self。我想将类型提示更新为子类的名称。不过,mypy==0.782正在报道error: Incompatible return value type (got "Foo[Bar]", expected "DFoo")  [return-value]。有什么办法可以做到这一点吗?**编辑**经过进一步思考,我决定重新解释这个问题。提前抱歉啰嗦了。基类 ( Foo) 有一个方法 ( get_self) 类型,暗示返回其自身的实例子类( DFoo)不重写方法然后子类使用 ( get_self) 方法并且知道返回类型实际上是子类的 ( DFoo)但是,静态类型检查器(例如mypy:)不知道子类的方法实际上会返回子类的对象,因为它们正在使用基类中的类型提示get_self因此,如果不使用新类型提示在子类中重新声明方法 (),我的问题可能无法实现。我可以使 的返回get_self成为 a TypeVar。然而,由于基类Foo已经是 a Generic,所以目前这是不可能的,因为它需要python/typing Higher-Kinded TypeVars #548中提到的“Higher-Kinded TypeVars” 。示例脚本我希望这能澄清我想要表达的意思。from __future__ import annotationsfrom typing import Generic, TypeVar, castT = TypeVar("T")class Foo(Generic[T]):    def get_self(self) -> Foo[T]:        # Other stuff happens here before the return        return selfclass Bar:    passclass 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"
查看完整描述

1 回答

?
HUWWW

TA贡献1874条经验 获得超12个赞

要解决这个问题,只需键入您的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 实际上并不要求您坚持使用此默认值。


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

查看完整回答
反对 回复 2023-08-22
  • 1 回答
  • 0 关注
  • 1340 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信