PEP 8 is Python's official style guide, and it has very specific rules about naming. Following these conventions makes your code instantly recognizable as "Pythonic" - the hallmark of professional Python code. Unlike JavaScript's camelCase or C#'s PascalCase everywhere, Python uses snake_case for most identifiers.
Why PEP 8 Matters
PEP 8 (Python Enhancement Proposal 8) was written by Python's creator Guido van Rossum and has become the de facto standard for Python code. Tools like pylint, flake8, and black all enforce PEP 8 rules. When you follow PEP 8:
- Your code is easier for other Python developers to read
- You can collaborate more effectively on open-source projects
- Automated tools can check and format your code
- Your code feels "Pythonic" rather than translated from another language
Convert to Python Naming
Transform JavaScript camelCase to Python snake_case instantly
snake_case - The Python Standard
Unlike most other languages, Python uses snake_case (all lowercase with underscores) for variables, functions, and methods. This is the most distinctive feature of Python naming.
Variables
All variable names should use snake_case:
# Good
user_name = "Alice"
total_count = 0
is_authenticated = False
shopping_cart_items = []
# Bad - don't do this in Python
userName = "Alice" # This is JavaScript style
TotalCount = 0 # This looks like a class
IsAuthenticated = False # Not Pythonic Functions and Methods
Function and method names also use snake_case:
# Good
def calculate_total(items):
return sum(item.price for item in items)
def get_user_data(user_id):
return database.query(user_id)
def is_valid_email(email):
return '@' in email
# Bad
def calculateTotal(items): # JavaScript style
pass
def GetUserData(user_id): # Looks like a class
pass Method Names in Classes
Instance methods follow the same snake_case convention:
class ShoppingCart:
def __init__(self):
self.items = []
def add_item(self, item):
"""Add item to cart - note snake_case"""
self.items.append(item)
def calculate_total(self):
"""Calculate total - also snake_case"""
return sum(item.price for item in self.items)
def is_empty(self):
"""Check if empty - snake_case for boolean methods too"""
return len(self.items) == 0PascalCase - Classes Only
In Python, PascalCase (also called CapWords) is reserved exclusively for class names. Every word starts with a capital letter, with no separators.
# Good - classes use PascalCase
class UserAccount:
pass
class DatabaseConnection:
pass
class PaymentProcessor:
pass
class HTTPClient: # Acronyms stay uppercase
pass
# Bad - don't use snake_case for classes
class user_account: # Looks like a function
pass
class database_connection: # Not Pythonic
pass Exception Classes
Exception classes should end with "Error" and use PascalCase:
class ValidationError(Exception):
pass
class DatabaseConnectionError(Exception):
pass
class InvalidInputError(ValueError):
passRelated Resources
SCREAMING_SNAKE_CASE - Constants
Constants in Python use all uppercase letters with underscores. These are module-level values that should never change.
# Good - constants at module level
MAX_CONNECTIONS = 100
API_BASE_URL = "https://api.example.com"
DEFAULT_TIMEOUT = 30
PI = 3.14159
# Use in code
if connection_count > MAX_CONNECTIONS:
raise ConnectionError("Too many connections")
# Constants in classes (class attributes)
class Config:
DATABASE_HOST = "localhost"
DATABASE_PORT = 5432
MAX_RETRIES = 3 What Counts as a Constant?
Use SCREAMING_SNAKE_CASE for:
- Module-level constants that never change
- Configuration values
- Mathematical constants (PI, E, etc.)
- Default values that are truly constant
Don't use it for:
- Variables that might change (even if they rarely do)
- Function results that you cache
- Class instances that happen to be singleton
Special Naming Patterns
Private and Internal Names
Python uses underscores to indicate privacy levels:
class User:
def __init__(self, name):
self.name = name # Public attribute
self._internal = None # Internal (convention)
self.__private = None # Private (name mangling)
def public_method(self):
"""Anyone can call this"""
pass
def _internal_method(self):
"""Internal use - convention only"""
pass
def __private_method(self):
"""Private - name gets mangled"""
pass Single Leading Underscore (_name)
Indicates "internal use" - a convention that says "don't use this outside this module/class, but it's not enforced."
Double Leading Underscore (__name)
Triggers name mangling - Python actually renames the attribute to _ClassName__name to avoid conflicts in subclasses. Use sparingly.
Double Leading and Trailing (__name__)
Reserved for Python's special methods (dunder methods). Don't create your own:
# These are defined by Python - don't make your own
def __init__(self): # Constructor
def __str__(self): # String representation
def __len__(self): # Length
def __getitem__(self, key): # Index access Boolean Variable Names
Unlike JavaScript, Python doesn't use "is" prefix for booleans (the methods already have "is" in the name for clarity):
# Good - simple adjectives
active = True
valid = False
authenticated = False
# Good - verb forms work too
has_permission = True
can_edit = False
# Avoid - redundant "is" prefix
is_active = True # Redundant
is_authenticated = True # Not Pythonic
# Methods can use "is" prefix
def is_valid(self): # Method name - this is fine
return self.validModule and Package Names
Module (file) names should be short, lowercase, and can use underscores:
# Good module names
utils.py
database.py
user_authentication.py
data_processing.py
# Bad module names
Utils.py # Don't capitalize
user-authentication.py # Use underscores, not hyphens
dataProcessing.py # Not camelCase Package (directory) names should be short and lowercase, preferably without underscores:
# Good package structure
mypackage/
__init__.py
core.py
utils.py
# Okay if needed
my_package/
__init__.py
# Bad
MyPackage/ # Don't capitalize
my-package/ # Can't use hyphens in importsCommon PEP 8 Mistakes
Mistake #1: Using camelCase for Functions
❌ def getUserData():
✓ def get_user_data():
Mistake #2: Using snake_case for Classes
❌ class user_account:
✓ class UserAccount:
Mistake #3: Lowercase Constants
❌ max_connections = 100
✓ MAX_CONNECTIONS = 100
Mistake #4: Creating Custom Dunder Methods
❌ def __my_method__(self):
✓ def my_method(self): or def _my_method(self):
PEP 8 Enforcement Tools
pylint
Comprehensive Python linter that checks naming conventions:
# Install
pip install pylint
# Run
pylint my_module.py
# Configure in .pylintrc
[BASIC]
good-names=i,j,k,_
bad-names=foo,bar,baz flake8
Fast linter focusing on style violations:
# Install
pip install flake8
# Run
flake8 my_module.py
# Configure in .flake8
[flake8]
max-line-length = 88
ignore = E203,W503 black
Opinionated code formatter that enforces PEP 8:
# Install
pip install black
# Format files
black my_module.py
# Check without changing
black --check my_module.pyReal-World Example
Here's a complete example showing all PEP 8 naming conventions:
"""User authentication module following PEP 8."""
# Module-level constants
MAX_LOGIN_ATTEMPTS = 3
SESSION_TIMEOUT = 3600
DEFAULT_ROLE = "guest"
class UserAccount:
"""Represents a user account in the system."""
def __init__(self, username, email):
self.username = username
self.email = email
self._login_attempts = 0
self.__password_hash = None
def authenticate(self, password):
"""Authenticate user with password."""
if self._login_attempts >= MAX_LOGIN_ATTEMPTS:
raise AuthenticationError("Too many login attempts")
if self._verify_password(password):
self._login_attempts = 0
return True
self._login_attempts += 1
return False
def _verify_password(self, password):
"""Internal password verification."""
# Implementation details
return True
def __repr__(self):
"""String representation of user."""
return f"UserAccount(username='{'self.username'}')"
class AuthenticationError(Exception):
"""Raised when authentication fails."""
pass
def create_user_account(username, email, role=DEFAULT_ROLE):
"""Create a new user account with given details."""
account = UserAccount(username, email)
account.role = role
return account
def is_valid_email(email):
"""Check if email format is valid."""
return "@" in email and "." in emailQuick Reference
| Type | Convention | Example |
|---|---|---|
| Variables | snake_case | user_name |
| Functions | snake_case | get_user_data() |
| Classes | PascalCase | UserAccount |
| Constants | SCREAMING_SNAKE_CASE | MAX_CONNECTIONS |
| Modules | lowercase | user_auth.py |
| Private | _leading_underscore | _internal_method |
Remember
- Use snake_case for nearly everything except classes
- Classes use PascalCase exclusively
- Constants use SCREAMING_SNAKE_CASE
- Single underscore prefix for internal/private
- Use tools like pylint and black to enforce