1

I was playing around new Python typing system and I faced concept which I don't know how to express in it. I want to pass the generic class type itself. E.g. to describe function which takes generic[1] G, type T and returns G[T].

I used mypy to check verify my tries.

The naive approach didn't work in 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 in Python 3.6's backport of typing?

There is GenericMeta is available in backport, but I didn't find how to use it and it didn't make it to PEP.

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

Mapping[Type, Type]?

I came up with Mapping, but apparently List is not such.

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)

Less strict works in Python 3.6 and 3.7

This is version I use for now. It catches some absurd calls like apply(10, int), but apply(int, int) will slip through static analysis and raise on runtime.

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

So the question comes is it possible to express generic type itself?

As for me, based on duck-typing, List should simply be Mapping[Type, Type]. I found PEP for protocols, maybe this is right tool for my problem?

[1] If I understand category theory right, such generic's type is technically named functor and is well known concept in languages like Haskell.

R2RT
  • 2,061
  • 15
  • 25

0 Answers0