Python typing.Literal: Restrict to Specific Values
Python's typing.Literal type hint enforces compile-time
constraints by restricting a variable, parameter, or return value to an
explicit set of distinct, predefined values. While traditional type
annotations like str or int permit any valid
value of those types, Literal narrows the allowed inputs to
exact values such as specific strings, integers, booleans, or
None. This article explains the syntax of
typing.Literal, how static type checkers interpret it, and
how it compares to alternative patterns like enumerations.
Understanding
typing.Literal
Introduced in Python 3.8 via PEP 586, Literal is part of
the standard typing module. It tells static analysis
tools—such as Mypy, Pyright, and IDE linters—that an expression must
equal one of the explicitly listed literal values.
from typing import Literal
# Restricting a variable to three specific string values
Mode = Literal["read", "write", "append"]
def open_file(path: str, mode: Mode) -> None:
pass
open_file("data.txt", "read") # Valid
open_file("data.txt", "execute") # Type checker error: Argument 2 has incompatible type "Literal['execute']"Supported Literal Types
Literal only accepts specific primitive values:
- Strings:
Literal["asc", "desc"] - Integers:
Literal[1, 2, 3] - Booleans:
Literal[True, False] None:Literal[None]- Bytes:
Literal[b"raw", b"processed"]
You can also combine different data types within a single
Literal definition:
from typing import Literal
Status = Literal["pending", 0, False]Passing multiple arguments into Literal[...] is
equivalent to combining them with typing.Union. Therefore,
Literal["read", "write"] is treated by type checkers
identically to
Union[Literal["read"], Literal["write"]].
Runtime vs. Static Behavior
Python's standard type hints, including Literal, do not
automatically enforce constraints at runtime. If an invalid value is
passed to a function at runtime, Python will execute the code unless
explicit validation logic or third-party validation libraries (like
Pydantic) are used.
# This executes without a Python runtime exception unless checked:
open_file("data.txt", "invalid_mode")The restriction is enforced during development by static analysis
engines. When using an IDE or running mypy script.py, the
type checker cross-references the assigned argument against the allowed
literals and reports an error before the code is deployed.
Common Use Cases
- Replacing "Magic Strings": Many APIs rely on
specific string parameters (e.g., HTTP methods
"GET","POST","PUT"). UsingLiteraldocuments the valid choices directly in the signature and provides autocompletion in code editors. - Function Overloading with Discriminated Unions:
Literalcan determine return types dynamically using@typing.overload. For example, a function can returnbyteswhen passedLiteral["bytes"]andstrwhen passedLiteral["text"].
typing.Literal vs.
enum.Enum
While enum.Enum also restricts inputs to specific
members, Literal is preferred when:
- You want callers to pass standard primitive types (like simple
strings or integers) without needing to import an
Enumclass. - You are typing existing libraries that already rely on specific string or integer flags.
- You need lightweight static guarantees without the runtime overhead of class creation.