Python hints Intro
Python has support for optional “type hints” (also called “type annotations”). These “type hints” or annotations are a special syntax that allow declaring the type of a variable. By declaring types for your variables, editors and tools can give you better support.
def get_full_name(first_name: str, last_name: str):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
Declaring Types
You just saw the main place to declare type hints. As function parameters. This is also the main place you would use them with FastAPI.
Simple types
You can declare all the standard Python types, not only str.
You can use, for example:
intfloatboolbytes
def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
return item_a, item_b, item_c, item_d, item_d, item_edef process_items(items: list[str]):
for item in items:
print(item)note:
Those internal types in the square brackets are called “type parameters”.
In this case, str is the type parameter passed to List (or list in Python 3.9 and above).
def process_items(items_t: tuple[int, int, str], items_s: set[bytes]):
return items_t, items_sThis means:
- The variable
items_tis atuplewith 3 items, anint, anotherint, and astr. - The variable
items_sis aset, and each of its items is of typebytes.
Dict
To define a dict, you pass 2 type parameters, separated by commas.
The first type parameter is for the keys of the dict.
The second type parameter is for the values of the dict:
def process_items(prices: dict[str, float]):
for item_name, item_price in prices.items():
print(item_name)
print(item_price)This means:
- The variable
pricesis adict:- The keys of this
dictare of typestr(let’s say, the name of each item). - The values of this
dictare of typefloat(let’s say, the price of each item).
- The keys of this
Union
You can declare that a variable can be any of several types, for example, an int or a str.
In Python 3.6 and above (including Python 3.10) you can use the Union type from typing and put inside the square brackets the possible types to accept.
In Python 3.10 there’s also a new syntax where you can put the possible types separated by a vertical bar (|).
def process_item(item: int | str):
print(item)In both cases this means that item could be an int or a str.
Possibly None
You can declare that a value could have a type, like str, but that it could also be None.
In Python 3.6 and above (including Python 3.10) you can declare it by importing and using Optional from the typing module.
from typing import Optional
def say_hi(name: Optional[str] = None):
if name is not None:
print(f"Hey {name}!")
else:
print("Hello World")Using Optional[str] instead of just str will let the editor help you detect errors where you could be assuming that a value is always a str, when it could actually be None too.
Optional[Something] is actually a shortcut for Union[Something, None], they are equivalent.
This also means that in Python 3.10, you can use Something | None:
def say_hi(name: str | None = None):
if name is not None:
print(f"Hey {name}!")
else:
print("Hello World")Classes as types
You can also declare a class as the type of a variable.
Let’s say you have a class Person, with a name:
class Person:
def __init__(self, name: str):
self.name = name
def get_person_name(one_person: Person):
return one_person.nameThen you can declare a variable to be of type Person:
class Person:
def __init__(self, name: str):
self.name = name
def get_person_name(one_person: Person):
return one_person.name[Pydantic] is a Python library to perform data validation.
Pydantic is a Python library to perform data validation.
You declare the “shape” of the data as classes with attributes.
And each attribute has a type.
Then you create an instance of that class with some values and it will validate the values, convert them to the appropriate type (if that’s the case) and give you an object with all the data.
And you get all the editor support with that resulting object.
An example from the official Pydantic docs:
from datetime import datetime
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str = "John Doe"
signup_ts: datetime | None = None
friends: list[int] = []
external_data = {
"id": "123",
"signup_ts": "2017-06-01 12:22",
"friends": [1, "2", b"3"],
}
user = User(**external_data)
print(user)
# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
print(user.id)
# > 123