#python #mypy #python-typing
#питон #мой #набор текста на python
Вопрос:
Рассмотреть:
from __future__ import annotations
class A:
@classmethod
def get(cls) -> A:
return cls()
class B(A):
pass
def func() -> B: # Line 12
return B.get()
Запустив mypy на этом, мы получаем:
$ mypy test.py
test.py:12: error: Incompatible return value type (got "A", expected "B")
Found 1 error in 1 file (checked 1 source file)
Кроме того, я проверил, работают ли рекурсивные аннотации в старом стиле. То есть:
# from __future__ import annotations
class A:
@classmethod
def get(cls) -> "A":
# ...
….. безрезультатно.
Конечно, можно было бы сделать:
from typing import cast
def func() -> B: # Line 12
return cast(B, B.get())
Каждый раз, когда всплывает это дело. Но я бы хотел избежать этого.
Как следует это напечатать?
Комментарии:
1. Я не уверен в том, о чем вы спрашиваете. Если вы хотите вернуть
A
, вам нужно явно указать его. Если вы просто хотите правильно аннотировать свою функцию, почему бы и нетdef func() -> A
?2. Я действительно хочу вернуться
B
func
. Например, предположим, что у нас есть классы, представляющие сущности базы данных. У нас есть общий классEntity
и подклассы, такие какUser
иProject
. У этих подклассов также есть дополнительные специфические атрибуты, которые имеют значение. Мы хотим четко указать, возвращаете ли вы aUser
илиProject
потому, что это ограничит то, что мы можем сделать ниже по потоку.
Ответ №1:
Параметры cls
и self
обычно выводятся с помощью mpyp
, чтобы избежать большого количества избыточного кода, но при необходимости они могут быть указаны явно с помощью аннотаций.
В этом случае явный тип для метода класса будет выглядеть следующим образом:
class A:
@classmethod
def get(cls: Type[A]) -> A:
return cls()
Итак, что нам действительно нужно здесь, так это способ создания Type[A]
универсального параметра, такого, чтобы при вызове метода класса из дочернего класса вы могли ссылаться на дочерний класс. К счастью, у нас есть TypeVar
значения для этого.
Работая с этим в вашем существующем примере, мы получим следующее:
from __future__ import annotations
from typing import TypeVar, Type
T = TypeVar('T')
class A:
@classmethod
def get(cls: Type[T]) -> T:
return cls()
class B(A):
pass
def func() -> B:
return B.get()
Теперь mypy
я снова должен быть твоим другом! 😎