3.1. Typing About
Also known as: "type annotations", "type hints", "gradual typing"
Types are not required, and never will be
Good IDE will give you hints
Types are used extensively in system libraries
More and more books and documentations use types
Introduced in Python 3.5
To type check use:
mypy
,pyre-check
,pytypes
Types are not required, and never will be. -- Guido van Rossum, Python initiator, core developer, former BDFL
It should 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. -- Python Software Foundation
3.1.1. Problem
>>> def add_numbers(a, b):
... return a + b
>>>
>>>
>>> add_numbers(1, 2)
3
>>> add_numbers(1.0, 2.0)
3.0
>>> add_numbers('a', 'b')
'ab'
>>> add_numbers(['a'], ['b'])
['a', 'b']
3.1.2. Solution 1
>>> def add_numbers(a, b):
... return a + b
>>>
>>>
>>> add_numbers(1, 2)
3
>>> add_numbers(1.0, 2.0)
3.0
>>> add_numbers('a', 'b')
'ab'
>>> add_numbers(['a'], ['b'])
['a', 'b']
3.1.3. Solution 2
>>> def add_numbers(a: int|float, b: int|float) -> int|float:
... return a + b
>>>
>>>
>>> add_numbers(1, 2)
3
>>> add_numbers(1.0, 2.0)
3.0
>>> add_numbers('a', 'b')
'ab'
>>> add_numbers(['a'], ['b'])
['a', 'b']
3.1.4. Python 2.X
>>> def add(a, b):
... """
... :param a: int
... :param b: int
... :return: int
... """
... return a + b
3.1.5. Python 2.7
>>> def add(a, b):
... # type: (int, int) -> int
... return a + b
3.1.6. Python 3.0
>>> def add(a: 'int', b: 'int') -> 'int':
... return a + b
3.1.7. Python 3.5
>>> def add(a: int, b: int) -> int:
... return a + b
3.1.8. Typing PEPs
Since Python 3.5: PEP 484 -- Type Hints
Since Python 3.6: PEP 526 -- Syntax for Variable Annotations
Since Python 3.8: PEP 544 -- Protocols: Structural subtyping (static duck typing)
Since Python 3.9: PEP 585 -- Type Hinting Generics In Standard Collections
Since Python 3.10: PEP 604 -- Allow writing union types as X | Y
PEP 482 -
literature overview on type hints
PEP 483 -
background on type hints
PEP 484 -
type hints
PEP 526 -
variable annotations and ClassVar
PEP 544 -
Protocol
PEP 561 -
distributing typed packages
PEP 563 -
from __future__ import annotations
PEP 585 -
subscriptable generics in the standard library
PEP 586 -
Literal
PEP 589 -
TypedDict
PEP 591 -
Final
PEP 593 -
Annotated
PEP 604 -
union syntax with |
PEP 612 -
ParamSpec
PEP 613 -
TypeAlias
PEP 646 -
variadic generics and TypeVarTuple
PEP 647 -
TypeGuard
PEP 649 -
(draft), from __future__ import co_annotations
PEP 655 -
Required and NotRequired
PEP 673 -
Self
PEP 675 -
LiteralString
PEP 677 -
(rejected), (int, str) -> bool callable type syntax
PEP 681 -
@dataclass_transform()
PEP 688 -
Buffer
PEP 692 -
Unpack[TypedDict] for **kwargs
PEP 695 -
class Class[T]: type parameter syntax
PEP 696 -
(draft), defaults for type variables
PEP 698 -
@override
PEP 702 -
(draft), @deprecated()
PEP 705 -
(draft), TypedMapping
3.1.9. Errors
Types are not Enforced
This code will run without any problems
Types are not required, and never will be
Although
mypy
,pyre-check
orpytypes
will throw error
>>> def add(a: int, b: int) -> int:
... return a + b
>>>
>>>
>>> add(1, 2)
3
>>>
>>> add(1.0, 2.0)
3.0
>>>
>>> add('a', 'b')
'ab'
3.1.10. Annotation
Annotation and definition can be separated
Two step process:
>>> x: int
>>> x = 1
One liner:
>>> x: int = 1
3.1.11. Annotation is not Definition
Two step process:
>>> print(a)
Traceback (most recent call last):
NameError: name 'a' is not defined
>>>
>>> a: int
>>>
>>> print(a)
Traceback (most recent call last):
NameError: name 'a' is not defined
>>>
>>> a = 1
>>> print(a)
1
Oneliner:
>>> print(b)
Traceback (most recent call last):
NameError: name 'b' is not defined
>>>
>>> b: int = 1
>>>
>>> print(b)
1
Even if the type is wrong, the code will run and the value will be assigned:
>>> print(c)
Traceback (most recent call last):
NameError: name 'c' is not defined
>>>
>>> c: int = 'one'
>>>
>>> print(c)
one
3.1.12. Dynamic Typing
good: fast development
bad: runtime errors (in projects with many developers)
>>> def add(a, b):
... return a + b
3.1.13. Static Typing
good: no runtime errors
bad: slow development
int add(int a, int b) {
return a + b;
}
float add(float a, float b) {
return a + b;
}
float add(int a, float b) {
return (float)a + b;
}
float add(float a, int b) {
return a + (float)b;
}
3.1.14. Gradual Typing
good: fast development
good: no runtime errors
Start:
>>> def add(a, b):
... return a + b
Later:
>>> def add(a: int, b: int):
... return a + b
Later:
>>> def add(a: int, b: int) -> int:
... return a + b
Later:
>>> def add(a: int|float, b: int|float) -> int|float:
... return a + b
3.1.15. Checkers
mypy
- the reference implementation for type checkerspyre
- written in OCaml and optimized for performancepyright
- a type checker that emphasizes speedpytype
- checks and infers types for unannotated code