Python Naming Conventions: The Complete PEP 8 Guide with Examples
PEP 8 naming conventions for Python variables, functions, classes, constants, and files — with before/after code examples, a linter reference, and a complete naming grid you can bookmark.
Python naming conventions and PEP 8 define exactly how variables, functions, classes, constants, and files should be named in Python code. Unlike style preferences in some languages, Python's conventions are codified in PEP 8 — the official style guide — and enforced automatically by linters like flake8, pylint, and ruff in virtually every professional Python project. Getting a camelCase variable name flagged in a code review is a common (and avoidable) experience for developers learning Python after JavaScript or Java.
Python naming conventions — the complete PEP 8 reference
Here is every Python naming convention in one place, colour-coded by convention type:
The most important takeaway: Python uses snake_case for almost everything — variables, functions, methods, module names, and file names. The only exceptions are class names (PascalCase) and constants (UPPER_SNAKE_CASE). If you remember only this, you will write PEP 8-compliant Python 95% of the time.
Python variable naming rules and examples
All Python variable names follow snake_case: all lowercase letters, with underscores separating words. Numbers are allowed but cannot start the name.
# ✅ Correct — PEP 8 snake_case
user_id = 42
first_name = "Alice"
item_count = 0
is_active = True
base_url = "https://api.example.com"
max_retry_count = 3
# ❌ Wrong — camelCase (Java/JavaScript style)
userId = 42
firstName = "Alice"
itemCount = 0
isActive = True
# ❌ Wrong — PascalCase (class style)
UserId = 42
FirstName = "Alice"Linter warning: If you use camelCase for a variable in Python, flake8 raises N806 (variable in function should be lowercase) or pylint raises C0103 (invalid-name). These warnings fire automatically in most CI/CD pipelines.
Special cases: A single underscore _ is used as a throwaway variable name — for loop variables you do not need:
# _ means "I don't need this value"
for _ in range(10):
do_something()
# __ is used to unpack when you only need part of a tuple
first, *_, last = [1, 2, 3, 4, 5]Python function naming with examples
Functions follow the same snake_case rule as variables. A well-named Python function reads like an English verb phrase:
# ✅ Correct — descriptive snake_case
def get_user_by_id(user_id: int) -> User:
...
def calculate_monthly_payment(principal, rate, term):
...
def parse_json_response(response_text: str) -> dict:
...
def is_valid_email(email: str) -> bool:
...
# ❌ Wrong — camelCase (JavaScript habit)
def getUserById(userId):
...
def calculateMonthlyPayment(principal, rate, term):
...Boolean functions conventionally start with is_, has_, or can_: is_authenticated(), has_permission(), can_retry().
Python class names — PascalCase explained
Class names are the main exception to snake_case. All Python class names use PascalCase (also called UpperCamelCase): every word starts with a capital letter, no underscores.
# ✅ Correct — PascalCase class names
class UserProfile:
pass
class DatabaseConnection:
pass
class HttpClientError(Exception): # Exception subclasses too
pass
class APIRateLimiter: # Acronyms treated as one word (API not A_P_I)
pass
# ❌ Wrong
class user_profile: # snake_case for a class
pass
class userProfile: # camelCase for a class
passException classes always end with Error or Exception: ValidationError, ConnectionTimeoutError, PaymentProcessingException. This is PEP 8 convention plus strong community standard — it immediately signals that the class is meant to be raised and caught.
The difference between snake_case and camelCase in Python
The most common confusion comes from developers moving between Python and JavaScript — the two most used languages, with opposite naming conventions for variables.
| Concept | Python (snake_case) | JavaScript (camelCase) | Java (camelCase) |
|---|---|---|---|
| Variable | user_first_name | userFirstName | userFirstName |
| Function | get_total_price() | getTotalPrice() | getTotalPrice() |
| Class | UserAccount | UserAccount | UserAccount |
| Constant | MAX_SIZE | MAX_SIZE | MAX_SIZE |
| File / module | user_service.py | userService.js | UserService.java |
The API mismatch problem: When a Python backend (FastAPI, Django) sends JSON to a JavaScript frontend, the names collide. Python uses first_name; JavaScript expects firstName.
The clean solution is to configure serialisation to auto-convert. In Pydantic (used by FastAPI):
from pydantic import BaseModel, ConfigDict
from pydantic.alias_generators import to_camel
class UserResponse(BaseModel):
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
first_name: str # stored as snake_case in Python
user_id: int # serialised as firstName, userId in JSONTo convert names manually between conventions, use the Snake Case Converter and Camel Case Converter.
Constants — UPPER_SNAKE_CASE
Module-level constants use all uppercase with underscores separating words. This makes constants immediately visually distinct from variables in any code reader.
# ✅ Module-level constants — UPPER_SNAKE_CASE
MAX_RETRIES = 3
DEFAULT_TIMEOUT = 30
API_BASE_URL = "https://api.example.com"
DATABASE_URL = "postgresql://localhost:5432/mydb"
# Used in environment-variable-backed settings
import os
SECRET_KEY = os.environ.get("SECRET_KEY", "")
DEBUG = os.environ.get("DEBUG", "False") == "True"How linters enforce PEP 8 naming automatically
You do not need to memorise every rule — linters catch violations in real time. Here are the three most-used Python linters and the naming codes they raise:
| Linter | Code | What it catches |
|---|---|---|
| flake8 + pep8-naming | N801 | Class name not CapWords (PascalCase) |
| flake8 + pep8-naming | N802 | Function name not lowercase |
| flake8 + pep8-naming | N803 | Argument name not lowercase |
| pylint | C0103 | Name doesn't conform to naming style (all types) |
| ruff | N* | All pep8-naming rules — fastest linter available |
Recommended setup for a new project:
# Install ruff (fastest, includes naming rules)
pip install ruff
# Run on your project
ruff check .
# Auto-fix what can be fixed
ruff check --fix .
# Add to pre-commit hook so it runs before every commit
# .pre-commit-config.yaml:
# - repo: https://github.com/charliermarsh/ruff-pre-commit
# hooks:
# - id: ruffKey takeaways
- Use snake_case for variables, functions, methods, modules, and file names.
- Use PascalCase for class names — the only exception to snake_case.
- Use UPPER_SNAKE_CASE for module-level constants.
- Use a single underscore prefix (
_name) for internal/private attributes. - Double underscores (
__name__) are reserved for Python dunder methods — do not invent your own. - Install ruff or flake8 with pep8-naming — the linter catches every violation automatically.
- Use Snake Case Converter to convert existing camelCase names to PEP 8 format.
Frequently asked questions
Why does Python use snake_case instead of camelCase?
Guido van Rossum chose snake_case for Python's standard library in the early 1990s, drawing on Unix/C conventions of the time. Readability studies since then have confirmed that snake_case is slightly easier to read than camelCase for multi-word identifiers — the underscores create clear word boundaries without relying on case detection. PEP 8 formalised this choice as the official convention in 2001.
Can I use camelCase in Python if my team prefers it?
Technically yes — Python will run the code either way. But doing so means disabling or suppressing naming rules in your linter, inconsistency with the standard library and most third-party libraries, and friction for any new developer who joins the project. PEP 8 is the community standard: deviating requires a stronger reason than personal preference.
How do Python naming conventions handle acronyms?
Treat acronyms as words. In snake_case: parse_html_content (not parse_HTML_content), api_client (not API_client). In PascalCase: HttpClient (not HTTPClient), ApiGateway (not APIGateway). The exception: established abbreviations where the all-caps version is universally recognised, like JSONDecoder or URLParser — both common in Python's stdlib.
What is the difference between _name and __name in Python?
Single underscore (_name) is a convention meaning "internal use" — it is not enforced by Python but signals to other developers not to use this attribute directly. Double underscore (__name) triggers name mangling — Python renames it to _ClassName__name to avoid conflicts in subclasses. Double underscores on both sides (__name__) are "dunder" methods reserved by Python — never create your own __custom__ attributes.
Does PEP 8 apply to Jupyter notebooks?
PEP 8 applies to any Python code, including notebooks. In practice, exploratory analysis notebooks are often less strict — single-letter variable names like df for DataFrame are universally accepted. But production-grade notebooks and those shared publicly benefit from PEP 8 compliance: it makes them far easier for others to read and adapt.
Free tool
Try the Snake Case Converter
Use our free snake case converter to calculate results instantly — no signup required.
Open Snake Case Converter →