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 = textBenefits
- 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_handTooling
- 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
- 820