2. Dynamically typing
The Python interpreter checks types as your code runs and the type of variable
can change during it’s lifetime
>>> thing = "hello"
>>> type(thing)
<class 'str'>
>>> thing = 29.0
>>> type(thing)
<class 'float'>
3. Static Typing
Static typing checks run without even running the program, usually when the code
is compiled (C++ and Java)
String thing;
thing = "Hello";
4. Duck Typing
“If it walks like a duck and it quacks like a duck, this it must be a duck”
You do not check types at all, instead you check if an object has a method or
attribute
>>> class Malort:
... def __str__(self):
... return "Jeppson's Malört"
... def __format__(self, format):
... if(format == 'where'):
... return "only in chicago"
... return "None"
...
>>> print(format(Malort(), "where"))
only in chicago
7. Optional Type Checking
- Compile-time type checking
- Easier to find bugs
- Less debugging
- Easier maintenance
- Machine-checked documentation
- Easier to understand code
- Grow from dynamic to static typing
- You can add static typing existing codebases after your code has matured
- You can gradually add type hints with Any
8. Why should you start type checking now?
● Great for complex and confusing code
● Good for open-source code
● Before migrating or refactoring code
9. PEP 484: Type Hints
Python will remain a dynamically typed language, and the authors have no desire
to ever make type hints mandatory, even by convention.
Type hints have no runtime effect
>>> def shot(location: str) -> str:
... if location == "new york":
... return "hennessy"
... elif location == "chicago":
... return "evan williams"
... else:
... return "jack daniels"
10. Function annotations
Functions can have annotation arguments and return value
>>> def beer(location: str, with_shot: bool = True) -> str:
...
>>> beer.__annotations__
{'location': <class 'str'>, 'with_shot': <class 'bool'>}
12. Type & Variable Comments
Annotations are great, but have not been backported to Python 2.x
Type comments can be used in any version of Python
>>> def beer(location, with_shot):
>>> # type: (str, bool) -> str
>>> ...
>>> speed_of_sound = 343.0 # type: float
13. Sequences & Mappings
Great we can do primitives but what about composite types. Also not an issue…
>>> beers: list = ["Coors Light", "Budweiser", "Corona"]
>>> shots: tuple = ("B-52", "Irish Car Bomb", "Lemon Drop")
>>> beer_shot: dict = {"Coors Light": "Jack Daniels", "Corona": "Tequila"}
14. Typing module
Composite types are great, but what about the individual values
>>> from typing import Dict, List, Tuple
>>> beers: List[str] = ["Coors Light", "Budweiser", "Corona"]
>>> shots: Tuple[str, str, str] = ("B-52", "Irish Car Bomb", "Lemon
Drop")
>>> beer_shot: Dict[str, str] = {"Coors Light": "Jack Daniels",
>>> ... "Corona": "Tequila"}
15. Sequences
Many times you expect some kind of sequence but do not care if it’s a list or a
tuple
>>> from typing import List, Sequence
>>>
>>> def take_shot(liquors: Sequence[str]) -> str:
>>> return random.choice(liquors)
16. Type Aliases
Instead of
Write this
>>> from typing import List, Tuple
>>>
>>> def take_shots(beer_shot: List[Tuple[str, str]]) -> Tuple[
>>> List[Tuple[str, str]],
>>> List[Tuple[str, str]],
>>> List[Tuple[str, str]],
>>> ]:
>>> return (beer_shot[0::3], beer_shot[1::3], beer_shot[2::3])
>>> from typing import List, Tuple
>>> Boilermaker = Tuple[str, str]
17. Functions without return values
>>> def shot(location: str) -> None:
... if location == "new york":
... print("hennessy")
... elif location == "chicago":
... print("evan williams")
... else:
... print("jack daniels")
>>> from typing import NoReturn
>>>
>>> def the_darkness() -> NoReturn:
raise Exception("It's too late")
18. The magically Any type
>>> from typing import Any, Sequence
>>>
>>> def take_shot(liquors: Sequence[Any]) -> Any:
>>> return random.choice(liquors)
19. The Optional Type
For functions that have a default value for an argument
>>> from typing import Sequence, Optional
>>>
>>> def beer_order(names: Sequence[str],
>>> ... start: Optional[str] = None) -> Sequence[str]:
20. The Union Type
When you need arguments of several types in a composite
>>> from typing import Union
>>>
>>> def beer_order(nashville_beer: Union[str, int]) -> Sequence[str]:
21. Annonating *args and **kwargs
>>> class Bar
>>> def __init__(self, beers: List[Beer],
>>> *customer: str,
>>> **drink_types: str) -> None:
>>> self.beers = beers