Skip to main content

Language Features

General

1. Dictionary Access

Accessing dictionary values: Always use [] syntax instead of .get(), unless you are using .get()’s optional argument to specify a default value.

script.python
value = data["key"]  # goodvalue = data.get("key")  # avoid (same behavior as above but doesn't error if key is missing)value = data.get("key", "default_value")  # good

There may be situations where you don't want to error if a key is missing but it's better to be explicit about what value is provided in the case that a key is missing. Allows for type of the value variable to be known no matter what just from reading.

2. Imports

Prefer absolute imports over relative imports for accessing parent modules. Use relative imports when the path would be overly long or importing within the same package.

script.python
from app.file_name import xyz  # goodfrom ..file_name import xyz  # avoid when possible

Also never use wildcard imports to make it clear which names are present in the namespace and make it easier to trace where a method came from.

script.python
from file_name import specific_method, HelperClass # goodfrom file_name import * # bad

3. String Templating / f-strings

Use f-strings instead of string concatenation.

script.python
f"Variable: {variable}" # good"Variable: " + str(variable) # bad (hard to read)

4. List Iterating

This isn't that serious but preference for pythonic list iterating such as zip() and enumerate()

script.python
for i, fruit in enumerate(fruits):    print(f"Index {i}: {fruit}")for name, score in zip(names, scores):    print(f"{name}: {score}")

5. Default Mutable Arguments

Never use default mutable arguments.

script.python
def add_to_list(num: int, lst: list[int] = []): # lst default value is [] which is mutable    lst.append(num)    return lstadd_to_list(5) # returns [5]add_to_list(6) # return [5, 6]

The default value keeps accumulating since it's mutable which is unexpected and can lead to difficult to debug bugs. Instead:

script.python
def add_to_list(num: int, lst: list[int] | None = None):    if not lst:        lst = []    lst.append(num)    return lst

Typing

Typing is a smaller language feature for Python when compared to Typescript so instead of getting it's own typing page as Typescript did, it is a subsection of language features.

1. Type hinting

Type hint all public functions and all FastAPI endpoints (inputs and outputs).

script.python
async def create_shapefile(self, latitude: float, longitude: float) -> str:
script.python
@router.get("/{uuid}/geojson", status_code=status.HTTP_200_OK, responses=GetGeojsonExampleResponses)async def get_shapefile_geojson(uuid: str, simplify: float | None = None) -> GeojsonConversionOut:

More details on typing FastAPI endpoint in FastAPI Specific page.

2. Typing collections

Use prebuilt generics for collections (e.g., list[str], dict[str, int]), as opposed to outdated typed collections from the typing module.

script.python
from typing import Dictdef xyz() -> Dict[str, int]: # bad, comes from typing moduledef xyz() -> dict[str, int]: # good, uses generics

3. Optional Values

Use | None for optional values (e.g., str | None) as opposed to Optional[str]

script.python
from typing import Optionalsimplify: Optional[float] = None # bad, slightly less readable and outdated syntaxsimplify: float | None = None # good

4. Any type

Avoid Any unless it is required; add a short comment explaining why.

5. Fixed dictionary shape

Use pydantic models when a dictionary object has a fixed shape.

script.python
from pydantic import BaseModelclass CreateSessionOut(BaseModel):    session_id: str    shapefiles: list[str]

6. Constrained string values

Always use Literal for constrained string values.

script.python
from typing import LiteralStatus = Literal["pending", "active", "disabled"]

Copyright © 2026 Atheesh Thirumalairajan