PEP 484: Clarify type erasure and instantiation of concrete collections (#193)

Fixes python/typing#367
This commit is contained in:
Ivan Levkivskyi 2017-02-01 01:27:53 +01:00 committed by Guido van Rossum
parent c9cf921546
commit ccae12b0ba
1 changed files with 29 additions and 18 deletions

View File

@ -544,9 +544,8 @@ However, there are some special cases in the static typechecking context:
Instantiating generic classes and type erasure
----------------------------------------------
Generic types like ``List`` or ``Sequence`` cannot be instantiated.
However, user-defined classes derived from them can be instantiated.
Suppose we write a ``Node`` class inheriting from ``Generic[T]``::
User-defined generic classes can be instantiated. Suppose we write
a ``Node`` class inheriting from ``Generic[T]``::
from typing import TypeVar, Generic
@ -583,27 +582,39 @@ the variable, e.g.::
a = Node() # type: Node[int]
b = Node() # type: Node[str]
You can also create a type alias (see above) for a specific concrete
type and instantiate it, e.g.::
Alternatively, you can instantiate a specific concrete type, e.g.::
# (continued from previous example)
IntNode = Node[int]
StrNode = Node[str]
p = IntNode() # Inferred type is Node[str]
q = StrNode() # Inferred type is Node[int]
r = IntNode('') # Error
s = StrNode(0) # Error
p = Node[int]()
q = Node[str]()
r = Node[int]('') # Error
s = Node[str](0) # Error
Note that the runtime type (class) of p and q is still just ``Node``
-- ``IntNode`` and ``StrNode`` are distinguishable class objects, but
the type (class) of the objects created by instantiating them doesn't
record the distinction. This behavior is called "type erasure"; it is
Note that the runtime type (class) of ``p`` and ``q`` is still just ``Node``
-- ``Node[int]`` and ``Node[str]`` are distinguishable class objects, but
the runtime class of the objects created by instantiating them doesn't
record the distinction. This behavior is called "type erasure"; it is
common practice in languages with generics (e.g. Java, TypeScript).
Generic versions of abstract collections like ``Mapping`` or ``Sequence``
and generic versions of built-in classes -- ``List``, ``Dict``, ``Set``,
and ``FrozenSet`` -- cannot be instantiated. However, concrete user-defined
subclasses thereof and generic versions of concrete collections can be
instantiated::
data = DefaultDict[int, bytes]()
Note that one should not confuse static types and runtime classes.
The type is still erased in this case and the above expression is
just a shorthand for::
data = collections.defaultdict() # type: DefaultDict[int, bytes]
It is not recommended to use the subscripted class (e.g. ``Node[int]``)
directly in an expression -- using a type alias instead is preferred.
(First, creating the subscripted class, e.g. ``Node[int]``, has a runtime
cost. Second, using a type alias is more readable.)
directly in an expression -- using a type alias (e.g. ``IntNode = Node[int]``)
instead is preferred. (First, creating the subscripted class,
e.g. ``Node[int]``, has a runtime cost. Second, using a type alias
is more readable.)
Arbitrary generic types as base classes