diff --git a/pep-0484.txt b/pep-0484.txt index 34595d86294..b75c8d01406 100644 --- a/pep-0484.txt +++ b/pep-0484.txt @@ -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 - -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 + 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`` +-- ``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