Универсальный тип, который действует как базовый тип

Я хочу создать общий тип 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 во время выполнения, когда я получаю переменную этого типа или проверяю сигнатуру функции.

Есть ли способ сделать это?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Один из способов — использовать псевдоним универсального типа, который возвращает единственный аргумент типа:

(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'>

Последнее предпочтительнее, особенно если вы хотите прикрепить метаданные к рассматриваемому типу.

Спасибо! Есть ли способ сделать это в Python 3.9?

Knoep 16.07.2024 21:00

@Knoep Посмотрите связанные игровые площадки Mypy; type A[T] = T — это всего лишь синтаксис версии 3.12+ для A: TypeAlias = T, с TypeAlias , импортированным из typing_extensions для версии 3.9 и старше.

InSync 16.07.2024 21:04

К сожалению, я получаю TypeError: 'TypeVar' object is not subscriptable при определении функции, если запускаю версию с TypeAlias на Python (mypy доволен).

Knoep 16.07.2024 21:44

@Knoep Верно, я забыл об этом. Затем используйте A = TypeAliasType('A', T).

InSync 16.07.2024 21:50

Отлично, это работает! Может быть, вы можете добавить это к ответу?

Knoep 16.07.2024 22:10

Обновил ответ соответственно.

InSync 16.07.2024 22:15

Другие вопросы по теме