forked from python/typing
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpep-0484.txt
1310 lines (942 loc) · 45.2 KB
/
pep-0484.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
PEP: 484
Title: Type Hints
Version: $Revision$
Last-Modified: $Date$
Author: Guido van Rossum <[email protected]>, Jukka Lehtosalo <[email protected]>, Łukasz Langa <[email protected]>
BDFL-delegate: Mark Shannon
Discussions-To: Python-Dev <[email protected]>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 29-Sep-2014
Post-History: 16-Jan-2015,20-Mar-2015,17-Apr-2015
Resolution:
Abstract
========
PEP 3107 introduced syntax for function annotations, but the semantics
were deliberately left undefined. There has now been enough 3rd party
usage for static type analysis that the community would benefit from
a standard vocabulary and baseline tools within the standard library.
This PEP introduces a provisional module to provide these standard
definitions and tools, along with some conventions for situations
where annotations are not available.
Note that this PEP still explicitly does NOT prevent other uses of
annotations, nor does it require (or forbid) any particular processing
of annotations, even when they conform to this specification. It
simply enables better coordination, as PEP 333 did for web frameworks.
For example, here is a simple function whose argument and return type
are declared in the annotations::
def greeting(name: str) -> str:
return 'Hello ' + name
While these annotations are available at runtime through the usual
``__annotations__`` attribute, *no type checking happens at runtime*.
Instead, the proposal assumes the existence of a separate off-line
type checker which users can run over their source code voluntarily.
Essentially, such a type checker acts as a very powerful linter.
(While it would of course be possible for individual users to employ
a similar checker at run time for Design By Contract enforcement or
JIT optimization, those tools are not yet as mature.)
The proposal is strongly inspired by mypy [mypy]_. For example, the
type "sequence of integers" can be written as ``Sequence[int]``. The
square brackets mean that no new syntax needs to be added to the
language. The example here uses a custom class ``Sequence``, imported
from a pure-Python module ``typing``. The ``Sequence[int]``
notation works by implementing ``__getitem__()`` in the metaclass.
The type system supports unions, generic types, and a special type
named ``Any`` which is consistent with (i.e. assignable to and from) all
types. This latter feature is taken from the idea of gradual typing.
Gradual typing and the full type system are explained in PEP 483.
Other approaches from which we have borrowed or to which ours can be
compared and contrasted are described in PEP 482.
Rationale and Goals
===================
PEP 3107 added support for arbitrary annotations on parts of a function
definition. Although no meaning was assigned to annotations then, there
has always been an implicit goal to use them for type hinting, which is
listed as the first possible use case in said PEP.
This PEP aims to provide a standard syntax for type annotations, opening
up Python code to easier static analysis and refactoring, potential
runtime type checking, and performance optimizations utilizing type
information.
Of these goals, static analysis is the most important. This includes
support for off-line type checkers such as mypy, as well as providing
a standard notation that can be used by IDEs for code completion and
refactoring.
Non-goals
---------
While the proposed typing module will contain some building blocks for
runtime type checking -- in particular a useful ``isinstance()``
implementation -- third party packages would have to be developed to
implement specific runtime type checking functionality, for example
using decorators or metaclasses. Using type hints for performance
optimizations is left as an exercise for the reader.
It should also be emphasized that Python will remain a dynamically
typed language, and the authors have no desire to ever make type hints
mandatory, even by convention.
What is checked?
================
Any function (or method -- for brevity we won't be repeating this)
with at least one argument or return annotation is checked, unless
type checking is disabled by the ``@no_type_check`` decorator or a
``# type: ignore`` comment (see below).
It is recommended but not required that checked function have
annotations for all its arguments and its return type. For a checked
function, the default annotation for arguments and for the return type
is ``Any``. An exception is that the first argument of instance and
class methods should not be annotated; it is assumed to have the type
of the containing class for instance method, and ``type`` for class
methods. Note that the return type of ``__init__`` ought to be
annotated with ``-> None`` (there is no exception for ``__init__``).
The body of a checked function is checked for consistency with the
given annotations. The annotations are also used to check correctness
of calls appearing in other checked functions.
Functions without any annotations (or whose checking is disabled) are
assumed to have type ``Any`` when they are referenced in checked
functions, and this should completely silence complaints from the
checker regarding those references (although a checker may still
request that a type be specified using a cast or a ``# type:`` comment
if a more specific type than ``Any`` is needed for analysis of
subsequent code).
A type checker should understand decorators; this may require
annotations on decorator definitions. In particular, a type checker
should understand the built-in decorators ``@property``,
``@staticmethod`` and ``@classmethod``. The first argument of a class
method should not be annotated; it is assumed to be a subclass of the
defining class.
Type Definition Syntax
======================
The syntax leverages PEP 3107-style annotations with a number of
extensions described in sections below. In its basic form, type
hinting is used by filling function annotation slots with classes::
def greeting(name: str) -> str:
return 'Hello ' + name
This states that the expected type of the ``name`` argument is
``str``. Analogically, the expected return type is ``str``.
Expressions whose type is a subtype of a specific argument type are
also accepted for that argument.
Acceptable type hints
---------------------
Type hints may be built-in classes (including those defined in
standard library or third-party extension modules), abstract base
classes, types available in the ``types`` module, and user-defined
classes (including those defined in the standard library or
third-party modules).
While annotations are normally the best format for type hints,
there are times when it is more appropriate to represent them
by a special comment, or in a separately distributed interface
file. (See below for examples.)
Annotations must be valid expressions that evaluate without raising
exceptions at the time the function is defined (but see below for
forward references).
The needs of static analysis require that annotations must be simple
enough to be interpreted by static analysis tools. In particular,
dynamically computed types are not acceptable. (This is an
intentionally somewhat vague requirement, specific inclusions and
exclusions may be added to future versions of this PEP as warranted by
the discussion.)
In addition to the above, the following special constructs defined
below may be used: ``None``, ``Any``, ``Union``, ``Tuple``,
``Callable``, all ABCs and stand-ins for concrete classes exported
from ``typing`` (e.g. ``Sequence`` and ``Dict``), type variables, and
type aliases.
All newly introduced names used to support features described in
following sections (such as ``Any`` and ``Union``) are available in
the ``typing`` module.
Using None
----------
When used in a type hint, the expression ``None`` is considered
equivalent to ``type(None)``.
Type aliases
------------
Type aliases are defined by simple variable assignments::
Url = str
def retry(url: Url, retry_count: int) -> None: ...
Note that we recommend capitalizing alias names, since they represent
user-defined types, which (like user-defined classes) are typically
spelled that way.
Type aliases may be as complex as type hints in annotations --
anything that is acceptable as a type hint is acceptable in a type
alias::
from typing import TypeVar, Iterable, Tuple
T = TypeVar('T', int, float, complex)
Vector = Iterable[Tuple[T, T]]
def inproduct(v: Vector) -> T:
return sum(x*y for x, y in v)
This is equivalent to::
from typing import TypeVar, Iterable, Tuple
T = TypeVar('T', int, float, complex)
def inproduct(v: Iterable[Tuple[T, T]]) -> T:
return sum(x*y for x, y in v)
Callable
--------
Frameworks expecting callback functions of specific signatures might be
type hinted using ``Callable[[Arg1Type, Arg2Type], ReturnType]``.
Examples::
from typing import Callable
def feeder(get_next_item: Callable[[], str]) -> None:
# Body
def async_query(on_success: Callable[[int], None],
on_error: Callable[[int, Exception], None]) -> None:
# Body
It is possible to declare the return type of a callable without
specifying the call signature by substituting a literal ellipsis
(three dots) for the list of arguments::
def partial(func: Callable[..., str], *args) -> Callable[..., str]:
# Body
Note that there are no square brackets around the ellipsis. The
arguments of the callback are completely unconstrained in this case
(and keyword arguments are acceptable).
Since using callbacks with keyword arguments is not perceived as a
common use case, there is currently no support for specifying keyword
arguments with ``Callable``. Similarly, there is no support for
specifying callback signatures with a variable number of argument of a
specific type.
Generics
--------
Since type information about objects kept in containers cannot be
statically inferred in a generic way, abstract base classes have been
extended to support subscription to denote expected types for container
elements. Example::
from typing import Mapping, Set
def notify_by_email(employees: Set[Employee], overrides: Mapping[str, str]) -> None: ...
Generics can be parametrized by using a new factory available in
``typing`` called ``TypeVar``. Example::
from typing import Sequence, TypeVar
T = TypeVar('T') # Declare type variable
def first(l: Sequence[T]) -> T: # Generic function
return l[0]
In this case the contract is that the returned value is consistent with
the elements held by the collection.
``TypeVar`` supports constraining parametric types to a fixed set of
possible types. For example, we can define a type variable that ranges
over just ``str`` and ``bytes``. By default, a type variable ranges
over all possible types. Example of constraining a type variable::
from typing import TypeVar
AnyStr = TypeVar('AnyStr', str, bytes)
def concat(x: AnyStr, y: AnyStr) -> AnyStr:
return x + y
The function ``concat`` can be called with either two ``str`` arguments
or two ``bytes`` arguments, but not with a mix of ``str`` and ``bytes``
arguments.
Note that subtypes of types constrained by a type variable are treated
as their respective explicitly listed base types in the context of the
type variable. Consider this example::
class MyStr(str): ...
x = concat(MyStr('apple'), MyStr('pie'))
The call is valid but the type variable ``AnyStr`` will be set to
``str`` and not ``MyStr``. In effect, the inferred type of the return
value assigned to ``x`` will also be ``str``.
Additionally, ``Any`` is a valid value for every type variable.
Consider the following::
def count_truthy(elements: List[Any]) -> int:
return sum(1 for elem in elements if element)
This is equivalent to omitting the generic notation and just saying
``elements: List``.
User-defined generic types
--------------------------
You can include a ``Generic`` base class to define a user-defined class
as generic. Example::
from typing import TypeVar, Generic
T = TypeVar('T')
class LoggedVar(Generic[T]):
def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name
self.logger = logger
self.value = value
def set(self, new: T) -> None:
self.log('Set ' + repr(self.value))
self.value = new
def get(self) -> T:
self.log('Get ' + repr(self.value))
return self.value
def log(self, message: str) -> None:
self.logger.info('{}: {}'.format(self.name message))
``Generic[T]`` as a base class defines that the class ``LoggedVar``
takes a single type parameter ``T``. This also makes ``T`` valid as
a type within the class body.
The ``Generic`` base class uses a metaclass that defines ``__getitem__``
so that ``LoggedVar[t]`` is valid as a type::
from typing import Iterable
def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
for var in vars:
var.set(0)
A generic type can have any number of type variables, and type variables
may be constrained. This is valid::
from typing import TypeVar, Generic
...
T = TypeVar('T')
S = TypeVar('S')
class Pair(Generic[T, S]):
...
Each type variable argument to ``Generic`` must be distinct. This is
thus invalid::
from typing import TypeVar, Generic
...
T = TypeVar('T')
class Pair(Generic[T, T]): # INVALID
...
You can use multiple inheritance with ``Generic``::
from typing import TypeVar, Generic, Sized
T = TypeVar('T')
class LinkedList(Sized, Generic[T]):
...
Arbitrary generic types as base classes
---------------------------------------
``Generic[T]`` is only valid as a base class -- it's not a proper type.
However, user-defined generic types such as ``LinkedList[T]`` from the
above example and built-in generic types and ABCs such as ``List[T]``
and ``Iterable[T]`` are valid both as types and as base classes. For
example, we can define a subclass of ``Dict`` that specializes type
arguments::
from typing import Dict, List, Optional
class Node:
...
class SymbolTable(Dict[str, List[Node]]):
def push(self, name: str, node: Node) -> None:
self.setdefault(name, []).append(node)
def pop(self, name: str) -> Node:
return self[name].pop()
def lookup(self, name: str) -> Optional[Node]:
nodes = self.get(name)
if nodes:
return nodes[-1]
return None
``SymbolTable`` is a subclass of ``dict`` and a subtype of ``Dict[str,
List[Node]]``.
If a generic base class has a type variable as a type argument, this
makes the defined class generic. For example, we can define a generic
``LinkedList`` class that is iterable and a container::
from typing import TypeVar, Iterable, Container
T = TypeVar('T')
class LinkedList(Iterable[T], Container[T]):
...
Now ``LinkedList[int]`` is a valid type. Note that we can use ``T``
multiple times in the base class list, as long as we don't use the
same type variable ``T`` multiple times within ``Generic[...]``.
Abstract generic types
----------------------
The metaclass used by ``Generic`` is a subclass of ``abc.ABCMeta``.
A generic class can be an ABC by including abstract methods
or properties, and generic classes can also have ABCs as base
classes without a metaclass conflict.
Forward references
------------------
When a type hint contains names that have not been defined yet, that
definition may be expressed as a string literal, to be resolved later.
A situation where this occurs commonly is the definition of a
container class, where the class being defined occurs in the signature
of some of the methods. For example, the following code (the start of
a simple binary tree implementation) does not work::
class Tree:
def __init__(self, left: Tree, right: Tree):
self.left = left
self.right = right
To address this, we write::
class Tree:
def __init__(self, left: 'Tree', right: 'Tree'):
self.left = left
self.right = right
The string literal should contain a valid Python expression (i.e.,
``compile(lit, '', 'expr')`` should be a valid code object) and it
should evaluate without errors once the module has been fully loaded.
The local and global namespace in which it is evaluated should be the
same namespaces in which default arguments to the same function would
be evaluated.
Moreover, the expression should be parseable as a valid type hint, i.e.,
it is constrained by the rules from the section `Acceptable type hints`_
above.
It is allowable to use string literals as *part* of a type hint, for
example::
class Tree:
...
def leaves(self) -> List['Tree']:
...
Union types
-----------
Since accepting a small, limited set of expected types for a single
argument is common, there is a new special factory called ``Union``.
Example::
from typing import Union
def handle_employees(e: Union[Employee, Sequence[Employee]]) -> None:
if isinstance(e, Employee):
e = [e]
...
A type factored by ``Union[T1, T2, ...]`` responds ``True`` to
``issubclass`` checks for ``T1`` and any of its subclasses, ``T2`` and
any of its subclasses, and so on.
One common case of union types are *optional* types. By default,
``None`` is an invalid value for any type, unless a default value of
``None`` has been provided in the function definition. Examples::
def handle_employee(e: Union[Employee, None]) -> None: ...
As a shorthand for ``Union[T1, None]`` you can write ``Optional[T1]``;
for example, the above is equivalent to::
from typing import Optional
def handle_employee(e: Optional[Employee]) -> None: ...
An optional type is also automatically assumed when the default value is
``None``, for example::
def handle_employee(e: Employee = None): ...
This is equivalent to::
def handle_employee(e: Optional[Employee] = None) -> None: ...
The ``Any`` type
----------------
A special kind of type is ``Any``. Every class is a subclass of
``Any``. This is also true for the builtin class ``object``.
However, to the static type checker these are completely different.
When the type of a value is ``object``, the type checker will reject
almost all operations on it, and assigning it to a variable (or using
it as a return value) of a more specialized type is a type error. On
the other hand, when a value has type ``Any``, the type checker will
allow all operations on it, and a value of type ``Any`` can be assigned
to a variable (or used as a return value) of a more constrained type.
Predefined constants
--------------------
Some predefined Boolean constants are defined in the ``typing``
module to enable platform-specific type definitions and such::
from typing import PY2, PY3, WINDOWS, POSIX
if PY2:
text = unicode
else:
text = str
def f() -> text: ...
if WINDOWS:
loop = ProactorEventLoop
else:
loop = UnixSelectorEventLoop
It is up to the type checker implementation to define their values, as
long as ``PY2 == not PY3`` and ``WINDOWS == not POSIX``. When the
program is being executed these always reflect the current platform,
and this is also the suggested default when the program is being
type-checked.
Compatibility with other uses of function annotations
=====================================================
A number of existing or potential use cases for function annotations
exist, which are incompatible with type hinting. These may confuse
a static type checker. However, since type hinting annotations have no
runtime behavior (other than evaluation of the annotation expression and
storing annotations in the ``__annotations__`` attribute of the function
object), this does not make the program incorrect -- it just may cause
a type checker to emit spurious warnings or errors.
To mark portions of the program that should not be covered by type
hinting, you can use one or more of the following:
* a ``# type: ignore`` comment;
* a ``@no_type_check`` decorator on a class or function;
* a custom class or function decorator marked with
``@no_type_check_decorator``.
For more details see later sections.
In order for maximal compatibility with offline type checking it may
eventually be a good idea to change interfaces that rely on annotations
to switch to a different mechanism, for example a decorator. In Python
3.5 there is no pressure to do this, however. See also the longer
discussion under `Rejected alternatives`_ below.
Type comments
=============
No first-class syntax support for explicitly marking variables as being
of a specific type is added by this PEP. To help with type inference in
complex cases, a comment of the following format may be used::
x = [] # type: List[Employee]
x, y, z = [], [], [] # type: List[int], List[int], List[str]
x, y, z = [], [], [] # type: (List[int], List[int], List[str])
x = [
1,
2,
] # type: List[int]
Type comments should be put on the last line of the statement that
contains the variable definition. They can also be placed on
``with`` statements and ``for`` statements, right after the colon.
Examples of type comments on ``with`` and ``for`` statements::
with frobnicate() as foo: # type: int
# Here foo is an int
...
for x, y in points: # type: float, float
# Here x and y are floats
...
The ``# type: ignore`` comment should be put on the line that the
error refers to::
import http.client
errors = {
'not_found': http.client.NOT_FOUND # type: ignore
}
A ``# type: ignore`` comment on a line by itself disables all type
checking for the rest of the file.
If type hinting proves useful in general, a syntax for typing variables
may be provided in a future Python version.
Casts
=====
Occasionally the type checker may need a different kind of hint: the
programmer may know that an expression is of a more constrained type
than the type checker infers. For example::
from typing import List, cast
def find_first_str(a: List[object]) -> str:
index = next(i for i, x in enumerate(a) if isinstance(x, str))
# We only get here if there's at least one string in a
return cast(str, a[index])
The type checker infers the type ``object`` for ``a[index]``, but we
know that (if the code gets to that point) it must be a string. The
``cast(t, x)`` call tells the type checker that we are confident that
the type of ``x`` is ``t``. At runtime a cast always returns the
expression unchanged -- it does not check the type, and it does not
convert or coerce the value.
Casts differ from type comments (see the previous section). When using
a type comment, the type checker should still verify that the inferred
type is consistent with the stated type. When using a cast, the type
checker should blindly believe the programmer. Also, casts can be used
in expressions, while type comments only apply to assignments.
Stub Files
==========
Stub files are files containing type hints that are only for use by
the type checker, not at runtime. There are several use cases for
stub files:
* Extension modules
* Complicated type signatures that, while useful to some tools,
are likely to obscure the intent of the code for human
reviewers.
* Third-party modules whose authors have not yet added type hints
* Standard library modules for which type hints have not yet been
written
* Modules that must be compatible with Python 2 and 3
* Modules that use annotations for other purposes
Stub files have the same syntax as regular Python modules. There is one
feature of the ``typing`` module that may only be used in stub files:
the ``@overload`` decorator described below.
The type checker should only check function signatures in stub files;
function bodies in stub files should just be a single ``pass``
statement.
The type checker should have a configurable search path for stub files.
If a stub file is found the type checker should not read the
corresponding "real" module.
While stub files are syntactically valid Python modules, they use the
``.pyi`` extension to make it possible to maintain stub files in the
same directory as the corresponding real module. This also reinforces
the notion that no runtime behavior should be expected of stub files.
Function overloading
--------------------
The ``@overload`` decorator allows describing functions that support
multiple different combinations of argument types. This pattern is
used frequently in builtin modules and types. For example, the
``__getitem__()`` method of the ``bytes`` type can be described as
follows::
from typing import overload
class bytes:
...
@overload
def __getitem__(self, i: int) -> int: pass
@overload
def __getitem__(self, s: slice) -> bytes: pass
This description is more precise than would be possible using unions
(which cannot express the relationship between the argument and return
types)::
from typing import Union
class bytes:
...
def __getitem__(self, a: Union[int, slice]) -> Union[int, bytes]: pass
Another example where ``@overload`` comes in handy is the type of the
builtin ``map()`` function, which takes a different number of
arguments depending on the type of the callable::
from typing import Callable, Iterable, Iterator, Tuple, TypeVar, overload
T1 = TypeVar('T1')
T2 = TypeVar('T2)
S = TypeVar('S')
@overload
def map(func: Callable[[T1], S], iter1: Iterable[T1]) -> Iterator[S]: pass
@overload
def map(func: Callable[[T1, T2], S],
iter1: Iterable[T1], iter2: Iterable[T2]) -> Iterator[S]: pass
# ... and we could add more items to support more than two iterables
Note that we could also easily add items to support ``map(None, ...)``::
@overload
def map(func: None, iter1: Iterable[T1]) -> Iterable[T1]: pass
@overload
def map(func: None,
iter1: Iterable[T1],
iter2: Iterable[T2]) -> Iterable[Tuple[T1, T2]]: pass
The ``@overload`` decorator may only be used in stub files. While it
would be possible to provide a multiple dispatch implementation using
this syntax, its implementation would require using
``sys._getframe()``, which is frowned upon. Also, designing and
implementing an efficient multiple dispatch mechanism is hard, which
is why previous attempts were abandoned in favor of
``functools.singledispatch()``. (See PEP 443, especially its section
"Alternative approaches".) In the future we may come up with a
satisfactory multiple dispatch design, but we don't want such a design
to be constrained by the overloading syntax defined for type hints in
stub files.
Storing and distributing stub files
-----------------------------------
The easiest form of stub file storage and distribution is to put them
alongside Python modules in the same directory. This makes them easy to
find by both programmers and the tools. However, since package
maintainers are free not to add type hinting to their packages,
third-party stubs installable by ``pip`` from PyPI are also supported.
In this case we have to consider three issues: naming, versioning,
installation path.
This PEP does not provide a recommendation on a naming scheme that
should be used for third-party stub file packages. Discoverability will
hopefully be based on package popularity, like with Django packages for
example.
Third-party stubs have to be versioned using the lowest version of the
source package that is compatible. Example: FooPackage has versions
1.0, 1.1, 1.2, 1.3, 2.0, 2.1, 2.2. There are API changes in versions
1.1, 2.0 and 2.2. The stub file package maintainer is free to release
stubs for all versions but at least 1.0, 1.1, 2.0 and 2.2 are needed
to enable the end user type check all versions. This is because the
user knows that the closest *lower or equal* version of stubs is
compatible. In the provided example, for FooPackage 1.3 the user would
choose stubs version 1.1.
Note that if the user decides to use the "latest" available source
package, using the "latest" stub files should generally also work if
they're updated often.
Third-party stub packages can use any location for stub storage. The
type checker will search for them using PYTHONPATH. A default fallback
directory that is always checked is ``shared/typehints/python3.5/`` (or
3.6, etc.). Since there can only be one package installed for a given
Python version per environment, no additional versioning is performed
under that directory (just like bare directory installs by ``pip`` in
site-packages). Stub file package authors might use the following
snippet in ``setup.py``::
...
data_files=[
(
'shared/typehints/python{}.{}'.format(*sys.version_info[:2]),
pathlib.Path(SRC_PATH).glob('**/*.pyi'),
),
],
...
Exceptions
==========
No syntax for listing explicitly raised exceptions is proposed.
Currently the only known use case for this feature is documentational,
in which case the recommendation is to put this information in a
docstring.
The ``typing`` Module
=====================
To open the usage of static type checking to Python 3.5 as well as older
versions, a uniform namespace is required. For this purpose, a new
module in the standard library is introduced called ``typing``. It
holds a set of classes representing builtin types with generics, namely:
* Dict, used as ``Dict[key_type, value_type]``
* List, used as ``List[element_type]``
* Set, used as ``Set[element_type]``. See remark for ``AbstractSet``
below.
* FrozenSet, used as ``FrozenSet[element_type]``
* Tuple, used by listing the element types, for example
``Tuple[int, int, str]``.
Arbitrary-length homogeneous tuples can be expressed
using one type and ellipsis, for example ``Tuple[int, ...]``.
(The ``...`` here are part of the syntax.)
* NamedTuple, used as
``NamedTuple(type_name, [(field_name, field_type), ...])``
and equivalent to
``collections.namedtuple(type_name, [field_name, ...])``.
The generic versions of concrete collection types (``Dict``, ``List``,
``Set``, ``FrozenSet``, and homogeneous arbitrary-length ``Tuple``)
are mainly useful for annotating return values. For arguments, prefer
the abstract collection types defined below, e.g. ``Mapping``,
``Sequence`` or ``AbstractSet``.
The ``typing`` module defines the ``Generator`` type for return values
of generator functions. It is a subtype of ``Iterable`` and it has
additional type variables for the type accepted by the ``send()``
method and the return type of the generator:
* Generator, used as ``Generator[yield_type, send_type, return_type]``
It also introduces factories and helper members needed to express
generics and union types:
* Any, used as ``def get(key: str) -> Any: ...``
* Union, used as ``Union[Type1, Type2, Type3]``
* TypeVar, used as ``X = TypeVar('X', Type1, Type2, Type3)`` or simply
``Y = TypeVar('Y')``
* Callable, used as ``Callable[[Arg1Type, Arg2Type], ReturnType]``
* AnyStr, defined as ``TypeVar('AnyStr', str, bytes)``
All abstract base classes available in ``collections.abc`` are
importable from the ``typing`` module, with added generics support:
* ByteString
* Callable (see above)
* Container
* Hashable (not generic, but present for completeness)
* ItemsView
* Iterable
* Iterator
* KeysView
* Mapping
* MappingView
* MutableMapping
* MutableSequence
* MutableSet
* Sequence
* Set, renamed to ``AbstractSet``. This name change was required
because ``Set`` in the ``typing`` module means ``set()`` with
generics.
* Sized (not generic, but present for completeness)
* ValuesView
A few one-off types are defined that test for single special methods
(similar to ``Hashable`` or ``Sized``):
* Reversible, to test for ``__reversed__``
* SupportsAbs, to test for ``__abs__``
* SupportsFloat, to test for ``__float__``
* SupportsInt, to test for ``__int__``
* SupportsRound, to test for ``__round__``
The library includes literals for platform-specific type hinting:
* PY2
* PY3, equivalent to ``not PY2``
* WINDOWS
* POSIX, equivalent to ``not WINDOWS``
The following conveniece functions and decorators are exported:
* cast, described earlier
* no_type_check, a decorator to disable type checking per class or
function (see below)
* no_type_check_decorator, a decorator to create your own decorators
with the same meaning as ``@no_type_check`` (see below)
* overload, described earlier
* get_type_hints, a utility function to retrieve the type hints from a
function or method. Given a function or method object, it returns
a dict with the same format as ``__annotations__``, but evaluating
forward references (which are given as string literals) as expressions
in the context of the original function or method definition.
The following types are available in the ``typing.io`` module:
* IO (generic over ``AnyStr``)
* BinaryIO (a simple subclass of ``IO[bytes]``)
* TextIO (a simple subclass of ``IO[str]``)
The following types are provided by the ``typing.re`` module:
* Match and Pattern, types of ``re.match()`` and ``re.compile()``
results (generic over ``AnyStr``)
As a convenience measure, types from ``typing.io`` and ``typing.re`` are
also available in ``typing`` (quoting Guido, "There's a reason those
modules have two-letter names.").
Rejected Alternatives
=====================
During discussion of earlier drafts of this PEP, various objections
were raised and alternatives were proposed. We discuss some of these