3.4. Type Annotation Callable¶
Before Python 3.9 you need
from typing import List, Set, Tuple, Dict
Since Python 3.9: PEP 585 -- Type Hinting Generics In Standard Collections
3.4.1. Return¶
>>> def say_hello() -> str:
... return 'My name... José Jiménez'
3.4.2. Required Parameters¶
>>> def add(a: int, b: int):
... return a + b
3.4.3. Optional Parameters¶
>>> def add(a: int = 1, b: int = 1):
... return a + b
3.4.4. Union¶
Since Python 3.10: PEP 604 -- Allow writing union types as X | Y
>>>
... def add(a: int | float, b: int | float) -> int | float:
... return a + b
3.4.5. Alias¶
Since Python 3.10: PEP 604 -- Allow writing union types as X | Y
>>> number = int | float
>>>
>>> def add(a: number, b: number) -> number:
... return a + b
3.4.6. Optional¶
Since Python 3.10: PEP 604 -- Allow writing union types as X | Y
>>> def say_hello(name: str | None) -> str | None:
... if name is not None:
... return f'Hello {name}'
3.4.7. Exception¶
>>> def on_timeout() -> Exception:
... raise TimeoutError
>>> def on_timeout() -> TimeoutError:
... raise TimeoutError
3.4.8. Literal¶
Since Python 3.8: PEP 586 -- Literal Types
Literal de-duplicates parameters
Equality comparisons of Literal objects are not order dependent
https://docs.python.org/3/library/typing.html#typing.Literal
>>> from typing import Literal
>>>
>>>
>>> def open(filename: str, mode: Literal['r','w','a']) -> None:
... pass
Usage:
>>> open('data.csv', mode='w') # mypy: OK
>>> open('data.csv', mode='r') # mypy: OK
>>> open('data.csv', mode='a') # mypy: OK
>>> open('data.csv', mode='x') # mypy: ERROR
3.4.9. Callable¶
Callable type
Callable[[int, int], float]
is a function of(int, int) -> float
There is no syntax to indicate optional or keyword arguments
https://docs.python.org/3/library/typing.html#typing.Callable
>>> from typing import Callable
>>>
>>>
>>> def run(func: Callable[[int, int], float]):
... ...
3.4.10. Iterator¶
>>> from typing import Iterator
>>>
>>>
>>> def fib(n: int) -> Iterator[int]:
... a, b = 0, 1
... while a < n:
... yield a
... a, b = b, a + b
3.4.11. Annotations¶
>>> def add(a: int, b: int) -> int:
... return a + b
>>>
>>>
>>> add.__annotations__
{'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}
3.4.12. Errors¶
Python will execute without even warning
Your IDE and
mypy
et. al. will yield errors
>>> def add(a: int, b: int) -> int:
... return a + b
>>>
>>>
>>> add('Mark', 'Watney')
'MarkWatney'
3.4.13. Good Engineering Practices¶
>>> def add(a: int | float,
... b: int | float,
... ) -> int | float:
... return a + b
3.4.14. Future¶
Since Python 3.11: PEP 563 -- Postponed Evaluation of Annotations
Since Python 3.11: PEP 675 -- Arbitrary Literal String Type
Postponed Evaluation of Annotations:
>>> def add(a: int, b: int) -> int:
... return a + b
>>>
>>>
... add.__annotations__
{'a': 'int', 'b': 'int', 'return': 'int'}
Arbitrary Literal String Type:
>>>
... def run_query(sql: LiteralString) -> ...
... ...
...
... def caller(
... arbitrary_string: str,
... query_string: LiteralString,
... table_name: LiteralString,
... ) -> None:
... run_query("SELECT * FROM students") # ok
... run_query(query_string) # ok
... run_query("SELECT * FROM " + table_name) # ok
... run_query(arbitrary_string) # type checker error
... run_query( # type checker error
... f"SELECT * FROM students WHERE name = {arbitrary_string}"
... )
3.4.15. Use Case - 0x01¶
>>> def valid_email(email: str) -> str | Exception:
... if '@' in email:
... return email
... else:
... raise ValueError('Invalid Email')
>>>
>>>
>>> valid_email('mark.watney@nasa.gov')
'mark.watney@nasa.gov'
>>>
>>> valid_email('mark.watney_at_nasa.gov')
Traceback (most recent call last):
ValueError: Invalid Email
3.4.16. Use Case - 0x02¶
>>> def find(text: str, what: str) -> int | None:
... position = text.find(what)
... if position == -1:
... return None
... else:
... return position
>>>
>>>
>>> find('Python', 'x')
>>> find('Python', 'o')
4
3.4.17. Use Case - 0x03¶
>>> from typing import Any
>>> import requests
>>>
>>>
>>> Result = requests.Response
>>>
>>> def fetch(url: str,
... on_success: Callable[[Result], Any],
... on_error: Callable[[Exception], Any],
... ) -> None:
... try:
... result: Result = requests.get(url)
... except Exception as err:
... on_error(err)
... else:
... on_success(result)
3.4.18. Further Reading¶
More information in Type Annotations
More information in CI/CD Type Checking