Seems like worrying about types takes away some of the beauty and simplicity of Python.
Seems un-pythonic -- isn't python supposed to by dynamically typed?
What about duck-typing?
Why add type hints?
Catching bugs preemptively
defuppercase(val):"""Takes a string and upper-cases it"""return val.upper()
uppercase("hello")
uppercase(6)
Perfectly sytactically valid
Results in a runtime error, but it would be nice to catch it beforehand
Why add type hints?
Catching bugs preemptively
Why add type hints?
Auto-Completion
Labeling types also are available to inform your editor about the objects in question
Your editor can figure out what methods are available on an object
Example: working with Path objects
Why add type hints?
Better code documentation
Makes the intended use of a function or class explicit
Allows you to make your duck-typing more explicit -- what exactly am I assuming will be the characteristics of the things that are passed in & returned from this function?
Did you just need an input that can be stringified?
Did you need an input that has a particular method?
Did you need something that can be iterated over?
Basic type hinting (str, int, etc.)
# Variables:# not needed in this case, unless you want to make sure you don't# accidentally reassign x to a different type
x: int = 0
x: float = 0.0# type-checker error, because x has already been declared
y = 0# type: int# Parameters and return typesdeffun(y: str) -> bool:
...
# class typesfrom pathlib import Path
defget_path() -> Path:
...
Basic type hinting (str, int, etc.)
Which raises a type error if you run a type-checker?
Go-to library: mypymypy-lang.org (though others exist)
Used by extension, or automatically in editors (python.linting.mypyEnabled = true)
Useful for automatic checking (CI/CD) -- can check the entire codebase for consistency (every time a function is called)
Types with parameters: Lists, Tuples & Dictionaries
Lists can, of course, take entries with any number of values. But, if you want to know what you can do with a given object, then specifying the type of entry that will be added is helpful.
If you assume it's a list of numbers, or strings, or dictionaries, type hints let you make that assumption explicit
Types with parameters: Lists
from typing importList
mylist1 = [] # mypy warns that you should add a type hint
mylist2: list = []
# doesn't give any more detail than the first,# just that it's a list of *something*
mylist3: List = [] # equivalent to the first two
mylist4: List[str] = [] # tells it it's a list of strings# No issues with mypy
mylist3.append(str)
mylist3.append(1.2)
# mypy error
mylist4.append(4)
Types with parameters, continued
mylist4: List[str] = []
...
for item in mylist4:
item.upper() # auto-complete works, because the editor knows what each entry is
Types with parameters, continued
from typing importDict, Tuple# Dictionaries
mydict1 = {} # mypy error -- should add type
mydict2: dict = {} # same as above, but explicit
mydict3: Dict = {} # same as above, but explicit
mydict4: Dict[str, float] # keys are strs, values are floats# Tuplesdefget_point() -> Tuple[float, float]:# returns a tuple of 2 floatsreturn1.0, 1.0
More complex types (Union, Optional, Any)
Any -- the broadest type possible (the opposite type is object).
Assumes that any method or property of the object does exist for typing purposes.
If possible, avoid using Any, but sometimes you have to (or at least have to for an initial pass)
defread_from_file_path(path: Union[Path, str]):ifisinstance(path, str): # inside this block, mypy knows this is a string
...
elifisinstance(path, Path):
...
More complex types (Union, Optional, Any)
# These three have the same types specified in 3 different waysdefcopy(directory: str, file: Union[str, None] = None):# Second parameter can be of type str or None
...
defcopy2(directory: str, file: Optional[str] = None):# Optional[arg] == Union[arg, None]
...
defcopy3(directory: str, file: str = None):# If you're defaulting a function argument to None, the# Optional is implied
...
Where to start
Start by adding types to new files/functions you create
Add types to existing code you understand well
Start with the easy cases, and handle more challenging types down the road (either by leaving types off certain things, using Any, or # type: ignore comments)