Yeah, PEP 585 should definitely get pushed through! That would be super useful all around.

Besides that, I think PEP 563 would mitigate most of the slowdown at runtime introduced by 604. The only exceptions would be explicit like assigning variables to types (int_list = List[int]) or dataclasses and the like.


And a sidenote on 563: wouldn't this pep allow us to use basic annotations without having to import typing (technically speaking)? For all PEP 563 cares, this would be valid code:

var1: List[Tuple[int, str]] # List and Tuple not imported
my_var: Definitely_not_a_type = 42

Maybe a complementary PEP to 563 would make it standard to use unresolved type annots without importing the typing module. Unless you have something that uses annotations at runtime, I don't see a need to import the library at all. Static analysis tools would import typing themselves to do their magic.

But that is also, unfortunately, pushing more work onto them and other tools like autocomplete...

On Fri, Mar 13, 2020 at 10:01 PM Guido van Rossum <> wrote:
I think we should try to get PEP 604 accepted, with the runtime option (a), since that's the way we've gone already.

PEP 604 proposes the right syntax, and I think mostly the right semantics (one could quibble about whether isinstance()/issubclass() ought to accept unions). Unfortunately it does not have a reasonable reference implementation. (The mypy patch looks okay, but the CPython patch is not realistic, since it attempts to import from the C code for |.)

There is another PEP, PEP 585, which is complete (in fact, we should just submit it to the SC for review!). There is also a basically complete implementation, in C. It introduces a C type types.GenericAlias (note: types, not typing!) which is used to represent generics involving builtins at runtime, e.g. after "a = list[int]", a.__origin__ points to 'list' and a.__args__ is the tuple (int,).

Here's an idea for an implementation of `a | b` based on that. A union could be an instance of types.GenericAlias whose __args__ is (a, b) and whose __origin__ points to some dummy type (implemented in C) that's only used to mark it as a union.