Read the body first

Development

Writing Python Code Like a Pro: A Deep Dive into Type Checking #2

You can see #1 here!

Dive into the world of Python typing with this in-depth guide. Learn how to use the typing module effectively and enhance your code's readability and maintainability. Get ready to become an expert in Python typing!

1. Using typing.Union for mutlple types

typing.Union comes in handy when a single function argument can have multiple types. Using Union ensures that your code is flexible and easier to understand.

from typing import Union

def process_message(msg: Union[str, bytes, None]) -> str:
    ...

The code above accepts arguments of type str, bytes, or None.

2. typing.Optional for the convenience

Simplify your code by replacing Union[<Type>, None] with typing.Optional.

from typing import Optional

def eat_food(food: Optional[str]) -> None:
    ...

In the code above, the food argument accepts either a str type or None.

Note

Starting from Python 3.10, you can use | instead of Union or Optional types. Thus, Union[str, bytes, None] can be written as str | bytes | None, and Optional[str]can be written asstr | None`.

3. Enhancing code clarity with typing.List, typing.Tuple, and typing.Dict

Specify types inside a list (array) using typing.List[<Type>]. For tuples, use typing.Tuple[<Type>, <Type>], and for dictionaries, use typing.Dict[<Key Type>, <Value Type>].

from typing import List, Tuple, Dict

names: List[str]
location: Tuple[int, int, int]
count_map: Dict[str, int]

Note

From Python 3.9 onwards, you can specify list, tuple, and dictionary types without importing the typing module, as shown below:

names: list[str]
location: tuple[int, int]
count_map: dict[str, int]

However, if you're building a library, using the typing module ensures compatibility with Python versions prior to 3.9. (Or you can use typing_extensions library for type compatibility)

4. Utilizing typing.TypedDict for flexible dictionary value types

Dictionaries may have value types that aren't fixed. In such cases, TypedDict comes to the rescue. Create a class that inherits from TypedDict, then map the key and value types as shown below (supported from Python 3.8):

from typing import TypedDict

class Person(TypedDict):
    name: str
    age: int
    gender: str

def calc_cost(person: Person) -> float:
    ...

Alternatively, you can write it like this:

from typing import TypedDict
Person = TypedDict("Person", name=str, age=str, gender=str)
Person = TypedDict("Person", {"name": str, "age": int, "gender": str})

Note

In many cases, TypedDict can be replaced with dataclass, which might be more appropriate for representing data objects (supported from Python 3.7):

from dataclasses import dataclass

@dataclass
class Person:
    name: str
    age: int
    gender: str

def calc_cost(person: Person) -> float:
    ...

Stay tuned for Part 3, where we'll explore more advanced typing concepts, including typing.Generator, typing.Iterable, typing.Iterator, typing.Callable, typing.Type, and typing.Any.