Naming Conventions, Constants, and Unpacking
Naming Conventions, Constants, and Unpacking
After reading this chapter, you will write clean, idiomatic PEP 8 Python code, leverage sequence unpacking, and understand how constants are declared and enforced.
Mental model
Python does not have a language-level const keyword. Instead, constant conventions are enforced through naming standards and static analysis tools like ruff and mypy.
Naming Categories:
┌──────────────────────────┬────────────────────────────┬────────────────────────┐
│ Pattern │ Convention │ Example │
├──────────────────────────┼────────────────────────────┼────────────────────────┤
│ snake_case │ Functions, variables, files│ db_connection_timeout │
│ UPPER_SNAKE_CASE │ Constants, globals │ MAX_RETRIES, HTTP_OK │
│ PascalCase (CapWords) │ Classes, Exception types │ DatabasePool, APIError │
│ _leading_underscore │ Internal / Private marker │ _internal_buffer │
│ __dunder__ │ Special Python protocols │ __init__, __repr__ │
└──────────────────────────┴────────────────────────────┴────────────────────────┘
Unpacking allows you to extract elements from an iterable directly into named variables in a single atomic statement without manual index indexing.
Minimal example
Save as unpacking_demo.py:
# unpacking_demo.py
def main() -> None:
# Atomic variable swap without temporary variable
left = "left_hand"
right = "right_hand"
left, right = right, left
print(f"Swapped: left={left}, right={right}")
# Extended star unpacking
endpoint_data = ("GET", "/api/v1/users", 200, "0.12ms", "192.168.1.10")
method, path, status, *telemetry = endpoint_data
print(f"Method : {method}")
print(f"Path : {path}")
print(f"Status : {status}")
print(f"Telemetry : {telemetry} (packed into a list)")
if __name__ == "__main__":
main()Run via uv run python unpacking_demo.py:
Swapped: left=right_hand, right=left_hand
Method : GET
Path : /api/v1/users
Status : 200
Telemetry : ['0.12ms', '192.168.1.10'] (packed into a list)
Worked examples
Case 1: Star unpacking in loops and data processing
You can cleanly separate headers, body items, and footers from structured data stream records:
# process_records.py
def process_stream() -> None:
records = [
("auth", "admin", "success", "10.0.0.1"),
("query", "select * from users", "success", "10.0.0.2"),
("error", "timeout on connection", "failed", "10.0.0.3"),
]
for event_type, *details, ip in records:
print(f"Event: {event_type:8s} | IP: {ip:12s} | Details: {' '.join(details)}")
if __name__ == "__main__":
process_stream()Run:
uv run python process_records.pyCase 2: Marking constant intent with typing.Final
While CPython allows rebinding uppercase variables, modern type checkers will flag modifications to variables marked with Final:
# constants_guard.py
from typing import Final
DATABASE_TIMEOUT_SECONDS: Final[int] = 30
MAX_CONNECTIONS: Final[int] = 100
def check_limits(requested: int) -> bool:
return requested <= MAX_CONNECTIONS
if __name__ == "__main__":
print(f"Timeout: {DATABASE_TIMEOUT_SECONDS}s")
print(f"Acceptable: {check_limits(50)}")Run:
uv run python constants_guard.pyPitfalls
Pitfall 1: Unbalanced unpacking assignments
coords = (10, 20, 30)
x, y = coords # ValueError: too many values to unpack (expected 2, got 3)
# Fix: Match length or use star expression:
x, y, _ = coords # Ignore the 3rd value using dummy variable "_"
x, *rest = coords # Capture remaining valuesPitfall 2: Overriding built-in functions with variable names
Never name variables after built-in functions like id, type, list, str, dict, or min:
# Dangerous:
list = [1, 2, 3] # Now the built-in "list()" constructor is masked in this scope!Exercises
- Write a script that unpacks a 5-element tuple into
first,middle(a list of 3 elements using*), andlast. - Write a script that unpacks nested coordinates:
entry = ("datacenter-east", (40.7128, -74.0060)). Extract the name and latitude/longitude in a single unpacking line. - Use
ruff checkon a file containing non-PEP8 variable names (likecamelCaseVariable = 10) to see how modern linters catch naming deviations.
Further reading
- PEP 8: Style Guide for Python Code (Naming Conventions section).
- PEP 3132: Extended Iterable Unpacking.
- Python Standard Library:
typing.Final.