У меня есть базовый класс 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
) не отменяет метод - Child class then uses the (
get_self
) method- And knows that the return type will actually be of the child class (
DFoo
)
- And knows that the return type will actually be of the child class (
- Однако средства проверки статического типа (например,
mypy
) не знают, что метод дочернего класса фактически вернет объект дочернего класса, поскольку они используют подсказку типа из базового класса.
Поэтому мой вопрос может быть невозможен без повторного объявления метода (get_self
) в дочернем классе с подсказкой нового типа.
Я мог бы сделать возвращение get_self
TypeVar
. Однако, поскольку базовый класс Foo
уже является Generic
, в настоящее время это невозможно, поскольку для этого потребуются высокопроизводительные TypeVars, упомянутые в python / typing Higher-Kinded TypeVars # 548.
Образец сценария
Я надеюсь, что это проясняет то, что я пытаюсь понять.
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
Foo[Bar]
не класс; это подсказка типа. - person chepner   schedule 21.09.2020Foo
не должен быть подклассомFoo[Bar]
? Насколько я понимаю, при вводеFoo[Bar]
это классFoo
с его аргументом типа =Bar
. - person Intrastellar Explorer   schedule 21.09.2020Foo
. - person chepner   schedule 21.09.2020[Bar]
из наследования, ошибка станет менее конкретной и останется присутствующей:error: Incompatible return value type (got "Foo[Any]", expected "DFoo")
. Возможно, мне что-то не хватает, но я не думаю, что аргумент типа дляDFoo
создает проблему в данном случае. - person Intrastellar Explorer   schedule 21.09.2020def do_something_get_self(self) -> Foo
? Он элегантен, полиморфен, не требует сложных определений или назначений. Кроме того, он точно описывает возвращаемый тип. - person Aviv Yaniv   schedule 23.09.2020DFoo
добавляет методы, и без указания типаDFoo
mypy
позже вызовет ошибку. Я обновил вопрос, включив в него это - person Intrastellar Explorer   schedule 23.09.2020self
, и мы хотим, чтобы в нашем классе была другая функция, которая активирует супер-метод и также возвращает self; мы можем сделать что-то вроде этого:def do_something_get_self(self) -> DFoo: self.get_self() return self
и избежать проблемы с подсказкой типа суперget_self
. - person Aviv Yaniv   schedule 23.09.2020def do_something_get_self(self) -> DFoo: self.get_self() return self
должно быть достаточным; вызываяget_self
и возвращаяself
, мы можем обойти проверку типов @IntrastellarExplorer, что вы думаете? - person Aviv Yaniv   schedule 25.09.2020get_self
в родительском классеFoo
заключалась в том, чтобы его можно было использовать для получения собственного экземпляра, а не обходить стороной только потому, чтоmypy
вызвал ошибку. Если вы видите выбранный ответ, это позволяет напрямуюreturn self.get_self()
. - person Intrastellar Explorer   schedule 26.09.2020