mypy 使用 child 的名称而不是 parent 方法的通用签名从 child 方法更新 return 值
mypy updating return value from child method using child's name instead of parent's method's generic signature
我有一个 Generic
基础 class,它 return 本身就是一种方法 (get_self
)。我已经打字提示了。
然后我有一个 child class 的基数 class,它为 Generic
传入一个类型参数。在childclass中,我调用get_self
。我想将类型提示更新为 child class.
的名称
但是,mypy==0.782
正在报告 error: Incompatible return value type (got "Foo[Bar]", expected "DFoo") [return-value]
。有什么办法可以做到这一点吗?
**编辑**
经过深思熟虑,我决定re-explain这个问题。提前抱歉冗长。
- Base class (
Foo
) 有一个方法 (get_self
) 类型提示 return 自身的一个实例
- Child class (
DFoo
) 不覆盖方法
- Child class 然后使用 (
get_self
) 方法
- 并且知道 return 类型实际上是 child class (
DFoo
)
- 然而,静态类型检查器(例如:
mypy
)并不知道 child class 的方法实际上 return 一个 object child class 中的,因为他们正在使用基础 class 中的类型提示
所以如果没有 re-declaring child class 中的方法 (get_self
) 和新类型提示,我的问题可能无法实现。
我可以将 get_self
的 return 设为 TypeVar
。但是,由于基础 class 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
要解决此问题,只需将 get_self
函数键入 def get_self(self: S) -> S
,其中 S 是某种类型的变量。
下面的程序将干净利落地进行类型检查:
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
的默认类型。虽然它通常会自动给出当前 class 的类型,但 PEP 484 实际上并不强制您坚持使用此默认值。
因此,我们将其改为泛型,以确保输出类型始终匹配当前子类型。
有关此交互的更多详细信息,请参阅 https://mypy.readthedocs.io/en/stable/generics.html#generic-methods-and-generic-self。
我有一个 Generic
基础 class,它 return 本身就是一种方法 (get_self
)。我已经打字提示了。
然后我有一个 child class 的基数 class,它为 Generic
传入一个类型参数。在childclass中,我调用get_self
。我想将类型提示更新为 child class.
但是,mypy==0.782
正在报告 error: Incompatible return value type (got "Foo[Bar]", expected "DFoo") [return-value]
。有什么办法可以做到这一点吗?
**编辑**
经过深思熟虑,我决定re-explain这个问题。提前抱歉冗长。
- Base class (
Foo
) 有一个方法 (get_self
) 类型提示 return 自身的一个实例 - Child class (
DFoo
) 不覆盖方法 - Child class 然后使用 (
get_self
) 方法- 并且知道 return 类型实际上是 child class (
DFoo
)
- 并且知道 return 类型实际上是 child class (
- 然而,静态类型检查器(例如:
mypy
)并不知道 child class 的方法实际上 return 一个 object child class 中的,因为他们正在使用基础 class 中的类型提示
所以如果没有 re-declaring child class 中的方法 (get_self
) 和新类型提示,我的问题可能无法实现。
我可以将 get_self
的 return 设为 TypeVar
。但是,由于基础 class 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
要解决此问题,只需将 get_self
函数键入 def get_self(self: S) -> S
,其中 S 是某种类型的变量。
下面的程序将干净利落地进行类型检查:
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
的默认类型。虽然它通常会自动给出当前 class 的类型,但 PEP 484 实际上并不强制您坚持使用此默认值。
因此,我们将其改为泛型,以确保输出类型始终匹配当前子类型。
有关此交互的更多详细信息,请参阅 https://mypy.readthedocs.io/en/stable/generics.html#generic-methods-and-generic-self。