2.4. Function Type Annotation¶
2.4.1. Rationale¶
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
2.4.2. Return¶
def say_hello() -> str:
return 'My name... José Jiménez'
2.4.3. Parameters¶
def add_numbers(a: int, b: int) -> int:
return a + b
add_numbers(1, 2)
# 3
2.4.4. Union¶
from typing import Union
def add_numbers(a: Union[int,float], b: Union[int,float]) -> Union[int,float]:
return a + b
add_numbers(1, 2) # 'Ok'
add_numbers(1.5, 2.5) # 'Ok'
from typing import Union
Number = Union[int, float]
def add_numbers(a: Number, b: Number) -> Number:
return a + b
add_numbers(1, 2) # 'Ok'
add_numbers(1.5, 2.5) # 'Ok'
Since Python 3.10: PEP 604 -- Allow writing union types as X | Y
def add_numbers(a: int|float, b: int|float) -> int|float:
return a + b
add_numbers(1, 2) # 'Ok'
add_numbers(1.5, 2.5) # 'Ok'
2.4.5. Optional¶
from typing import Union
def find(text: str, what: str) -> Union[int,None]:
position = text.find(what)
if position == -1:
return None
else:
return position
find('Python', 'o') # 4
find('Python', 'x') # None
from typing import Optional
def find(text: str, what: str) -> Optional[int]:
position = text.find(what)
if position == -1:
return None
else:
return position
find('Python', 'o') # 4
find('Python', 'x') # None
Since Python 3.10: PEP 604 -- Allow writing union types as X | Y
def find(text: str, what: str) -> int|None:
position = text.find(what)
if position == -1:
return None
else:
return position
find('Python', 'o') # 4
find('Python', 'x') # None
Since Python 3.10: PEP 645 -- Allow writing optional types as x?
def find(text: str, what: str) -> int?:
position = text.find(what)
if position == -1:
return None
else:
return position
find('Python', 'o') # 4
find('Python', 'x') # None
2.4.6. NoReturn¶
from typing import NoReturn
def stop() -> NoReturn:
raise RuntimeError
from typing import Union, NoReturn
def valid_email(email: str) -> Union[NoReturn, str]:
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
2.4.7. Literal¶
Since Python 3.8: PEP 586 -- Literal Types
from typing import Literal
def open(filename: str, mode: Literal['r','w','a']) -> None:
pass
open('data.csv', mode='w') # Ok
open('data.csv', mode='r') # Ok
open('data.csv', mode='a') # Ok
open('data.csv', mode='x') # Error
2.4.8. Annotations¶
def add(a: int, b: int) -> int:
return a + b
add.__annotations__
# {'a': <class 'int'>,
# 'b': <class 'int'>,
# 'return': <class 'int'>}
Since Python 3.10: PEP 563 -- Postponed Evaluation of Annotations
def add(a: int, b: int) -> int:
return a + b
add.__annotations__
# {'a': 'int',
# 'b': 'int',
# 'return': 'int'}
2.4.9. Errors¶
Python will execute without even warning
Your IDE and
mypy
et. al. will yield errors
def add_numbers(a: int, b: int) -> int:
return a + b
add_numbers('Mark', 'Watney')
# 'MarkWatney'
2.4.10. Good Engineering Practices¶
from typing import Union
def add_numbers(a: Union[int,float],
b: Union[int,float]
) -> Union[int,float]:
return a + b
add_numbers(1, 2) # 'Ok'
add_numbers(1.5, 2.5) # 'Ok'
2.4.11. Further Reading¶
More information in Type Annotations
More information in CI/CD Type Checking