Как аннотировать сам тип typing.Generic?

Я играл с новой системой типизации Python и столкнулся с концепцией, которую не знаю, как в ней выразить. Я хочу передать сам общий тип класса. Например. для описания функции, которая принимает универсальную[1] G, набирает T и возвращает G[T].

Я использовал mypy, чтобы проверить мои попытки.

Наивный подход не работал в Python 3.7.

from typing import Generic, Type, List, Mapping, TypeVar

T = TypeVar('T')

def foo(generic: Generic, param: Type[T]) -> Generic[T]: #  error: Invalid type "typing.Generic"
    return generic[param] #  error: Value of type "Generic?[T?]" is not indexable

ListOfInts: Type = foo(List, int)

assert ListOfInts == List[int] # passes in runtime

Naive GenericMeta в бэкпорте Python 3.6 для typing?

GenericMeta доступна в backport, но я не нашел, как ее использовать, и она не не дойти до PEP.

def foo(generic: GenericMeta, param: Type[T]) -> Type[Type[T]]:
    return generic[param] #  error: Value of type "GenericMeta" is not indexable

Сопоставление[Тип, Тип]?

Я придумал Mapping, но видимо List не такой.

def apply(generic: Mapping[Type, Type], param: Type[T]) -> Type[Type[T]]:
    return generic[param]

# error: Argument 1 to "apply" has incompatible type "Type[List[Any]]"; expected "Mapping[Type[Any], Type[Any]]"
ListOfInts: Type = apply(List, int)

Менее строго работает в Python 3.6 и 3.7

Это версия, которую я использую на данный момент. Он перехватывает некоторые абсурдные вызовы, такие как apply(10, int), но apply(int, int) пропускается при статическом анализе и поднимается во время выполнения.

def apply(generic: Type, param: Type[T]) -> Type[Type[T]]:
    return generic[param]

Итак, возникает вопрос, возможно ли выразить сам общий тип?

Что касается меня, то на основе утиного набора List должно быть просто Mapping[Type, Type]. Я нашел PEP для протоколов, возможно, это подходящий инструмент для моей проблемы?

[1] Если я правильно понимаю теорию категорий, такой общий тип технически называется функтор и является хорошо известной концепцией в таких языках, как Haskell.


person R2RT    schedule 18.05.2019    source источник