What is TypedDict
TypedDict is a feature introduced in Python 3.8, as part of the typing module. It allows you to specify type hints for dictionaries, where you can denote expected keys and their corresponding value types. TypedDict does not enforce these types at runtime; instead, it's used for static type checking tools, improving the readability and maintainability of your code.
Creating TypedDict
Creating a TypedDict in Python is straightforward. First, you need to import the TypedDict
class from the typing
module. Then, you define your TypedDict as a new class that inherits from TypedDict
. Inside this class, you define the keys and their associated types.
Let's create a simple TypedDict for a user's profile:
from typing import TypedDict
class UserProfile(TypedDict):
name: str
age: int
email: str
In the example above, we have created a TypedDict named UserProfile
. According to its definition, a dictionary of type UserProfile
should have keys name
, age
, and email
, with their respective types being str
, int
, and str
.
Now that we've defined our UserProfile
TypedDict, let's see how to use it:
def display_user(profile: UserProfile) -> None:
print(f"Name: {profile['name']}")
print(f"Age: {profile['age']}")
print(f"Email: {profile['email']}")
user: UserProfile = {
'name': 'Alice',
'age': 30,
'email': 'alice@example.com'
}
display_user(user)
In the code above, we first define a function display_user
that takes a UserProfile
dictionary as an argument and prints out the user's information. Then, we create a user dictionary according to the UserProfile
TypedDict we defined earlier, and call display_user
with user
as the argument.
The type hint in the function signature helps ensure that the display_user
function always receives the correct type of dictionary. If we try to call display_user
with a dictionary that doesn't conform to the UserProfile
TypedDict (for example, if it's missing a key or a key has a value of the wrong type), we'll get a type error.
Optional Keys in TypedDict
While the TypedDict we created in the previous sections required all keys to be present and of a certain type, it's also possible to define TypedDicts with optional keys. This can be done using the total
parameter in the TypedDict definition.
Consider a scenario where an email address is optional in the user's profile. We can represent this by setting total=False
in our UserProfile
definition:
from typing import TypedDict
class UserProfile(TypedDict, total=False):
name: str
age: int
email: str
Now, a UserProfile
can either have an email
key or not, and it will still be valid:
def display_user(profile: UserProfile) -> None:
print(f"Name: {profile['name']}")
print(f"Age: {profile['age']}")
if 'email' in profile:
print(f"Email: {profile['email']}")
user: UserProfile = {
'name': 'Alice',
'age': 30
}
display_user(user)
In this code, we've modified the display_user
function to only print the email address if it's present in the profile. We then create a user
dictionary without an email address, and display_user(user)
runs without any errors.
Nested TypedDicts
TypedDicts can also be nested to represent more complex data structures. Consider a scenario where the user profile includes an address, which itself is a dictionary with several fields:
from typing import TypedDict
class Address(TypedDict):
street: str
city: str
state: str
zip_code: str
class UserProfile(TypedDict):
name: str
age: int
email: str
address: Address
In this code, we've defined an Address
TypedDict, and then used it in the definition of UserProfile
. Now a UserProfile
includes an address
key, whose value should be an Address
dictionary.
TypedDict and Inheritance
TypedDicts also support inheritance. This can be useful when you have several types of dictionaries that share some fields but also have their own unique fields.
For instance, consider a scenario where, in addition to user profiles, we also have admin profiles. Admins have all the same fields as users, but they also have an additional permissions
field:
class AdminProfile(UserProfile):
permissions: list[str]
In this code, we define AdminProfile
as a subclass of UserProfile
, and add an additional permissions
field. Now an AdminProfile
is expected to have all the fields of a UserProfile
, plus a permissions
field.
References