PythonConstants

Constants

A constant is a value that is meant to stay the same throughout a program’s execution — things like a mathematical constant, a configuration limit, or a fixed label. Python has no built-in mechanism to make a variable truly unchangeable; constants are entirely a matter of convention and, optionally, static-analysis tooling.

Python Has No True Constants
Warning
Unlike languages with a `const` keyword, Python cannot prevent a variable from being reassigned. Writing `MAX_USERS = 100` creates a perfectly ordinary variable — nothing stops later code (accidentally or otherwise) from executing `MAX_USERS = 200`. “Constant” status in Python is a promise enforced by convention and tooling, not by the language runtime.

Python
MAX_USERS = 100
print(MAX_USERS)  # 100

MAX_USERS = 200    # Python allows this without complaint
print(MAX_USERS)   # 200 -- nothing enforced it was "constant"
The ALL_CAPS Convention

By convention (PEP 8), names intended to act as constants are written in ALL_CAPS_WITH_UNDERSCORES. This is purely visual — it signals intent to other developers reading the code, but Python itself treats these names exactly like any other variable.

Python
PI = 3.14159
MAX_CONNECTIONS = 100
DEFAULT_TIMEOUT_SECONDS = 30
API_BASE_URL = "https://api.example.com"

def calculate_circle_area(radius):
    return PI * radius ** 2
Why Use Constants: Avoiding Magic Numbers

A “magic number” (or magic string) is a literal value scattered through code with no explanation of what it means. Replacing magic values with named constants makes code self-documenting and gives you a single place to change the value later.

Python
# Hard to understand: what is 0.08? what is 3?
def total_cost(price, quantity):
    return price * quantity * 1.08

# Clearer: the constant names explain themselves
TAX_RATE = 0.08

def total_cost(price, quantity):
    return price * quantity * (1 + TAX_RATE)
typing.Final: Enforcement via Static Checkers

Since Python 3.8, the typing module provides Final, an annotation that tells static type checkers (like mypy or your editor’s type checker) that a name should never be reassigned. It has zero effect at runtime — Python still won’t stop a reassignment when the program actually runs — but it lets tooling catch the mistake before you ship it.

Python
from typing import Final

MAX_RETRIES: Final = 3
API_VERSION: Final[str] = "v2"

# A static checker (mypy) would flag the next line as an error,
# even though Python itself would run it just fine:
# MAX_RETRIES = 5   # error: Cannot assign to final name "MAX_RETRIES"
Note
`Final` is a hint for tools, not a runtime guard. Running `python script.py` will not raise any error if you reassign a `Final` variable — you need `mypy` (or a similar checker) running in your workflow for it to actually catch the mistake.
A More Robust Alternative: enum.Enum

When you have a group of related constants (say, the possible statuses of an order), Python’s enum module is a much more robust tool than a handful of loose ALL_CAPS variables. Enum members are distinct, comparable, and immutable by design.

Python
from enum import Enum

class OrderStatus(Enum):
    PENDING = "pending"
    SHIPPED = "shipped"
    DELIVERED = "delivered"
    CANCELLED = "cancelled"

order_status = OrderStatus.SHIPPED

print(order_status)              # OrderStatus.SHIPPED
print(order_status.name)         # SHIPPED
print(order_status.value)        # shipped
print(order_status == OrderStatus.SHIPPED)  # True

for status in OrderStatus:
    print(status.name, status.value)

Compared to plain ALL_CAPS variables, enums group related values under one namespace, prevent accidental typos (OrderStatus.SHIPED is an AttributeError, not a silent bug), and make invalid values impossible to construct by accident.

Choosing an Approach

Approach

Enforcement

Best For

ALL_CAPS variable

None — pure convention

A single, standalone constant (PI, MAX_RETRIES).

typing.Final

Static-checker only, no runtime effect

Signalling intent when your team already runs mypy.

enum.Enum

Structural — members are fixed, distinct objects

A closed group of related named values (statuses, roles, directions).

Key Takeaways
  • Python has no true constants — any name can be reassigned at any time.

  • ALL_CAPS naming is the universal convention signaling "treat this as a constant."

  • Named constants replace magic numbers/strings, making code self-documenting.

  • typing.Final gives static checkers (not the runtime) the ability to flag reassignment.

  • enum.Enum is the most robust option for a fixed, related group of constant values.