Short introduction to Type Hints in Python
Problem
def resolve_all(items):
for item in items:
item.case.resolve()
def cancel_all(items):
resolve_all(items)
notify_all(items)
...
- What are the items? List, dict, something else? What is the particular item - an object? What does it represent?
- Does it always have `case` attribute?
- Are we sure that items are passed correctly? Maybe they're `None`?
Potential solutions
- External documentation
- Internal documentation (comments, explicit naming)
- Being very careful (defensive programming)
- Type hints
Type hints
- PEP 484 -- Type Hints
- PEP 526 -- Syntax for Variable Annotations
Examples
def notify(who: User, message: str = 'Default message') -> None:
...
def count_chars(text: str) -> Dict[str, int]:
...
class ExampleClass:
text: str = 'Some text'
number: int
def __init__(self, number: int, text: str = ''):
self.number = number
if text:
self.text = text
Benefits
- Static type checking - less bugs in production
- Better discoverability & readability
- We can treat them as additional documentation
- Improved IDE experience
- Dataclasses - PEP 557
Dataclass example
@dataclass
class InventoryItem:
'''Class for keeping track of an item in inventory.'''
name: str
unit_price: float
quantity_on_hand: int = 0
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
Tooling
- mypy - http://mypy-lang.org/
- pyright - https://github.com/microsoft/pyright
- MonkeyType - https://github.com/Instagram/MonkeyType
- injector - https://github.com/alecthomas/injector
- dacite - https://github.com/konradhalas/dacite
from typing import Dict, List, Optional
class ExampleClass:
text: str = 'Some text'
number: int
def __init__(self, number: int, text: str = ''):
self.number = number
if text:
self.text = text
def iterate(self, vals: Optional[List[int]]) -> None:
for val in vals:
print(val)
def notify(who: Optional[ExampleClass], message: str = 'Default message') -> None:
return who.notify()
ex = ExampleClass(111)
ex.nonexistent
notify(ex)
another = ExampleClass('123')
> mypy ex1.py
ex1.py:14: error: Item "None" of "Optional[List[int]]" has no attribute "__iter__" (not iterable)
ex1.py:19: error: Item "ExampleClass" of "Optional[ExampleClass]" has no attribute "notify"
ex1.py:19: error: Item "None" of "Optional[ExampleClass]" has no attribute "notify"
ex1.py:24: error: "ExampleClass" has no attribute "nonexistent"
ex1.py:28: error: Argument 1 to "ExampleClass" has incompatible type "str"; expected "int"
Short introduction to Type Hints in Python
By progressive
Short introduction to Type Hints in Python
- 645