← Python lessons

Python Optional and Union Types: int | None and X | Y

A Python union type, such as int | str, allows either type. int | None means an integer or no value.

Allow more than one type

Use | between types in Python 3.10 or later.

def label(value: int | str) -> str:
    return f"ID: {value}"

print(label(12))
print(label("guest"))

This prints ID: 12 and ID: guest.

Handle a value that might be None

Check is None before doing arithmetic. After that check, a type checker can narrow the type.

def next_score(score: int | None) -> int:
    if score is None:
        return 0
    return score + 1

print(next_score(None))
print(next_score(8))

This prints 0 and 9. Check is None, since 0 is a valid integer too.

Read Optional and Union annotations

Optional[int] means int | None. Union[int, str] means int | str.

from typing import Optional, Union

def label(value: Union[int, str], score: Optional[int] = None) -> str:
    if score is None:
        return str(value)
    return f"{value}: {score}"

print(label("Ada"))
print(label("Ada", 8))

This prints Ada and Ada: 8. These spellings also work in older Python versions.

Note: Allowing None does not make an argument optional to pass. A default such as = None lets callers omit it. Hints do not enforce types at runtime.

See also: Type hints, If and else.

Your turn

Complete show_score: return "Missing" for None, otherwise return str(score).

def show_score(score: int | None) -> str:
    # add three lines: check for None and return Missing, otherwise return str(score)
    pass

print(show_score(None))
print(show_score(0))

Expected output

Missing
0

Practise this in the free Python course, where every exercise checks your code instantly.