@@ -462,41 +462,58 @@ Suppose we write a ``Node`` class inheriting from ``Generic[T]``::
462
462
class Node(Generic[T]):
463
463
...
464
464
465
- Now there are two ways we can instantiate this class; the type
466
- inferred by a type checker may be different depending on the form we
467
- use. The first way is to give the value of the type parameter
468
- explicitly -- this overrides whatever type inference the type
469
- checker would otherwise perform::
465
+ To create ``Node`` instances you call ``Node()`` just as for a regular
466
+ class. At runtime the type (class) of the instance will be ``Node``.
467
+ But what type does it have to the type checker? The answer depends on
468
+ how much information is available in the call. If the constructor
469
+ (``__init__`` or ``__new__``) uses ``T`` in its signature, and a
470
+ corresponding argument value is passed, the type of the corresponding
471
+ argument(s) is substituted. Otherwise, ``Any`` is assumed. Example::
470
472
471
- x = Node[T]() # The type inferred for x is Node[T].
472
-
473
- y = Node[int]() # The type inferred for y is Node[int].
474
-
475
- If no explicit types are given, the type checker is given some
476
- freedom. Consider this code::
477
-
478
- x = Node()
479
-
480
- The inferred type could be ``Node[Any]``, as there isn't enough
481
- context to infer a more precise type. Alternatively, a type checker
482
- may reject the line and require an explicit annotation, like this::
483
-
484
- x = Node() # type: Node[int] # Inferred type is Node[int].
473
+ from typing import TypeVar, Generic
485
474
486
- A type checker with more powerful type inference could look at how
487
- ``x`` is used elsewhere in the file and try to infer a more precise
488
- type such as ``Node[int]`` even without an explicit type annotation.
489
- However, it is probably impossible to make such type inference work
490
- well in all cases, since Python programs can be very dynamic.
475
+ T = TypeVar('T')
491
476
492
- This PEP doesn't specify the details of how type inference should
493
- work. We allow different tools to experiment with various approaches.
494
- We may give more explicit rules in future revisions .
477
+ class Node(Generic[T]):
478
+ def __init__(self, label: T = None) -> None:
479
+ .. .
495
480
496
- At runtime the type is not preserved, and the class of ``x`` is just
497
- ``Node`` in all cases. This behavior is called "type erasure"; it is
481
+ x = Node('') # Inferred type is Node[str]
482
+ y = Node(0) # Inferred type is Node[int]
483
+ z = Node() # Inferred type is Node[Any]
484
+
485
+ In case the inferred type uses ``[Any]`` but the intended type is more
486
+ specific, you can use a type comment (see below) to force the type of
487
+ the variable, e.g.::
488
+
489
+ # (continued from previous example)
490
+ a = Node() # type: Node[int]
491
+ b = Node() # type: Node[str]
492
+
493
+ You can also create a type alias (see above) for a specific concrete
494
+ type and instantiate it, e.g.::
495
+
496
+ # (continued from previous example)
497
+ IntNode = Node[int]
498
+ StrNode = Node[str]
499
+ p = IntNode() # Inferred type is Node[str]
500
+ q = StrNode() # Inferred type is Node[int]
501
+ r = IntNode('') # Error
502
+ s = StrNode(0) # Error
503
+
504
+ Note that the runtime type (class) of p and q is still just ``Node``
505
+ -- ``IntNode`` and ``StrNode`` are distinguishable class objects, but
506
+ the type (class) of the objects created by instantiating them doesn't
507
+ record the distinction. This behavior is called "type erasure"; it is
498
508
common practice in languages with generics (e.g. Java, TypeScript).
499
509
510
+ You cannot use the subscripted class (e.g. ``Node[int]``) directly in
511
+ an expression -- you must define a type alias. (This restriction
512
+ exists because creating the subscripted class, e.g. ``Node[int]``, is
513
+ an expensive operation -- usually many times as expensive as
514
+ constructing an instance of it. Using a type alias is also more
515
+ readable.)
516
+
500
517
501
518
Arbitrary generic types as base classes
502
519
---------------------------------------
0 commit comments