Я хочу создать общий тип A[T], который действует точно так же, как T, за исключением того, что во время выполнения я могу сказать, что на самом деле это тип A[T], а не T.
Я пытался
class A(Generic[T], T):
pass
но это, похоже, не работает, поскольку, например, mypy жалуется, что A[str] имеет тип object.
В качестве примера я хочу, чтобы что-то вроде этого проходило проверку типа:
def f(s: A[str]):
return re.findall('foo|bar', s)
Но при этом каким-то образом можно отличить A[str] от str во время выполнения, когда я получаю переменную этого типа или проверяю сигнатуру функции.
Есть ли способ сделать это?






Один из способов — использовать псевдоним универсального типа, который возвращает единственный аргумент типа:
(playground links: Mypy , Pyright)
type A[T] = T
def f(s: A[str]) -> None:
reveal_type(s) # str
re.findall('foo|bar', s) # fine
f('') # fine
>>> type(inspect.get_annotations(f)['s'])
<class 'types.GenericAlias'>
В старых версиях Python используйте typing_extensions.TypeAliasType:
from typing import TypeVar
from typing_extensions import TypeAliasType
T = TypeVar('T')
A = TypeAliasType('A', T, type_params = (T,))
# ^^^^^^^^^^^^^^^^^^ This part is optional
Другой способ — использовать Annotated[]:
(playground links: Mypy , Pyright)
from typing import Annotated
# There must be at least two arguments
def f(s: Annotated[str, 'Whatever']) -> None:
reveal_type(s) # str
re.findall('foo|bar', s) # fine
f('') # fine
>>> type(inspect.get_annotations(f)['s'])
<class 'typing._AnnotatedAlias'>
Последнее предпочтительнее, особенно если вы хотите прикрепить метаданные к рассматриваемому типу.
@Knoep Посмотрите связанные игровые площадки Mypy; type A[T] = T — это всего лишь синтаксис версии 3.12+ для A: TypeAlias = T, с TypeAlias , импортированным из typing_extensions для версии 3.9 и старше.
К сожалению, я получаю TypeError: 'TypeVar' object is not subscriptable при определении функции, если запускаю версию с TypeAlias на Python (mypy доволен).
@Knoep Верно, я забыл об этом. Затем используйте A = TypeAliasType('A', T).
Отлично, это работает! Может быть, вы можете добавить это к ответу?
Обновил ответ соответственно.
Спасибо! Есть ли способ сделать это в Python 3.9?