One of the new features of Python 3.10 is TypeAlias. The example given is as follows.

 1 2  StrCache = 'Cache[str]' # a type alias LOG_PREFIX = 'LOG[DEBUG]' # a module constant 

It can be written as.

 1 2  StrCache: TypeAlias = 'Cache[str]' # a type alias LOG_PREFIX = 'LOG[DEBUG]' # a module constant 

This makes StrCache more of a type alias than a string variable that clearly looks like Cache[str] (which it is).

This article is not about TypeAlias per se, but rather about Cache[str], which shows that Python seems to support Java-like generics, like Python’s built-in support for List[str] or list[str].

So let’s see how Python can implement a Cache[str] Cache that can only hold strings, but not other types.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14   from typing import TypeVar, Generic T = TypeVar('T') class Cache(Generic[T]): def __init__(self) -> None: self.items: dict[str, T] = {} def put(self, key: str, item: T) -> None: self.items[key] = item # Line 13 def get(self, key: str) -> T: return self.items.get(key) 

We are still using Python’s typing module, so the above code is still in the realm of class type hints, which is not a constraint on the Python interpreter and only affects checking tools like mypy.

using the above class.

 1 2 3 4 5 6 7  cache = Cache[str]() cache.put('a', 'abc') print(cache.get('a')) cache.put('b', 123) # Line 21 print(cache.get('b')) 

The command python test.py works fine and the output is as follows.

 1 2  abc 123 

But in IntelliJ IDEA, the fifth line above, the cache.put('b', 123) line, prompts:

 1  Expected type 'str' (matched generic type 'T'), got 'int' instead 

If you use mypy to detect.

 1 2 3 4  \$ mypy tt.py tt.py:13: error: Incompatible return value type (got "Optional[T]", expected "T") tt.py:21: error: Argument 2 to "put" of "Cache" has incompatible type "int"; expected "str" Found 2 errors in 1 file (checked 1 source file) 

In addition to Generic, TypeVar used above, typing module has more type constraints like Mapping, Iterator, Sequence and more Java-like generic functions.

## Generic subtypes

  1 2 3 4 5 6 7 8 9 10  from typing import TypeVar, Generic T = TypeVar('T') class Cache(Generic[T]): pass class TTLCache(Cache[T]): pass 

## Generic functions

 1 2 3 4 5 6  from typing import TypeVar, Sequence T = TypeVar('T') # Declare type variable def first(seq: Sequence[T]) -> T: # Generic function return seq[0] 

There are more uses than can be listed here. The need to write your own implementation code using generics is not really big, unless you do a third-party generic library that will use generic writing, which makes it clearer for others to use.