Python Naming Conventions
The definitive guide to PEP 8 naming standards and best practices
Python PEP 8 Naming at a Glance:
- Variables & Functions: snake_case →
user_email,get_user_data() - Classes: PascalCase →
UserProfile - Constants: UPPER_SNAKE_CASE →
MAX_CONNECTIONS - Private: Prefix with underscore →
_internal_method - Protected: Single underscore →
_protected_var
What is PEP 8?
PEP 8 is Python's official style guide, created by Guido van Rossum (Python's creator). It defines naming conventions, code layout, and best practices that the Python community follows to maintain consistency across projects.
1. snake_case for Functions and Variables
Python uses snake_case (all lowercase with underscores between words) for function names, variable names, and module names.
Variables
# ✅ Good - PEP 8 compliant
user_name = "John Doe"
user_age = 25
is_logged_in = True
shopping_cart_items = []
total_price = 0.0
# ❌ Bad - Not PEP 8
userName = "John" # camelCase (JavaScript style)
UserName = "John" # PascalCase
username = "John" # okay for single word, but lacks clarity
SHOPPING_CART = [] # UPPER_CASE (for constants only)Functions
# ✅ Good
def get_user_by_id(user_id):
"""Retrieve user from database by ID."""
return database.query(user_id)
def calculate_total_price(items):
"""Calculate sum of all item prices."""
return sum(item.price for item in items)
def send_email_notification(email, message):
"""Send email to specified address."""
# Implementation
pass
# ❌ Bad
def getUserById(id): # camelCase
pass
def GetUserById(id): # PascalCase
pass
def getuserbyid(id): # no separation
passBoolean Variables
# Prefix with is_, has_, can_, should_
is_active = True
has_permission = False
can_edit = True
should_validate = False
# Lists/collections: use plural nouns
users = []
active_users = []
completed_tasks = []2. PascalCase for Classes
Use PascalCase (CapWords) for class names. Each word starts with a capital letter, with no underscores.
# ✅ Good
class UserAccount:
"""Represents a user account."""
def __init__(self, username, email):
self.username = username
self.email = email
def get_user_info(self):
"""Return formatted user information."""
return f"{self.username} ({self.email})"
class ShoppingCart:
"""Shopping cart with items."""
pass
class PaymentProcessor:
"""Process payment transactions."""
pass
class HTTPClient:
"""HTTP client for API requests."""
# Acronyms like HTTP can be all caps
pass
# ❌ Bad
class user_account: # snake_case
pass
class userAccount: # camelCase
pass
class USERACCOUNT: # all caps
pass3. UPPER_SNAKE_CASE for Constants
Constants should use all uppercase letters with underscores separating words. Typically defined at module level.
# ✅ Good - Module-level constants
MAX_CONNECTIONS = 100
DEFAULT_TIMEOUT = 30
API_BASE_URL = "https://api.example.com"
DATABASE_HOST = "localhost"
HTTP_STATUS_OK = 200
# Constants can be grouped in classes too
class Config:
MAX_UPLOAD_SIZE = 5 * 1024 * 1024 # 5MB
ALLOWED_EXTENSIONS = {'.txt', '.pdf', '.png'}
DEFAULT_PAGE_SIZE = 20
# ❌ Bad
max_connections = 100 # looks like a variable
MaxConnections = 100 # PascalCase
MAXCONNECTIONS = 100 # no separation4. Private and Protected Names
Protected (Single Underscore)
Single leading underscore indicates "internal use" - a weak internal use indicator.
class BankAccount:
def __init__(self, balance):
self._balance = balance # Protected attribute
def _validate_amount(self, amount): # Protected method
"""Internal validation method."""
return amount > 0
def deposit(self, amount):
"""Public method."""
if self._validate_amount(amount):
self._balance += amountPrivate (Double Underscore)
Double leading underscore triggers name mangling to avoid name conflicts in subclasses.
class SecureAccount:
def __init__(self, balance):
self.__balance = balance # Name mangled to _SecureAccount__balance
def __encrypt_data(self, data): # Name mangled method
"""Private encryption method."""
return encrypted
def get_balance(self):
"""Public method accessing private data."""
return self.__balance
# Python mangles __balance to _SecureAccount__balance
account = SecureAccount(1000)
print(account.get_balance()) # ✅ Works
print(account.__balance) # ❌ AttributeError
print(account._SecureAccount__balance) # ✅ Works (but shouldn't do this)5. Module and Package Names
# ✅ Good module names (lowercase, short, no underscores if possible)
utils.py
helpers.py
config.py
database.py
# Underscores okay if improves readability
user_service.py
api_client.py
data_processor.py
# Package structure
myproject/
__init__.py
user_auth/
__init__.py
login.py
logout.py
data_processing/
__init__.py
parsers.py
validators.py
# ❌ Bad
UserService.py # PascalCase
API_Client.py # Mixed case
data-processor.py # hyphens not allowed6. Special Method Names (Dunder Methods)
Methods with double underscores before and after (dunder/magic methods) are reserved by Python.
class UserProfile:
def __init__(self, name):
"""Constructor."""
self.name = name
def __str__(self):
"""String representation."""
return f"UserProfile({self.name})"
def __repr__(self):
"""Developer representation."""
return f"UserProfile(name='{self.name}')"
def __eq__(self, other):
"""Equality comparison."""
return self.name == other.name
def __len__(self):
"""Return length."""
return len(self.name)
# Common dunder methods:
# __init__, __str__, __repr__, __len__, __getitem__,
# __setitem__, __delitem__, __iter__, __next__,
# __enter__, __exit__, __call__, __eq__, __lt__7. Type Hints and Type Aliases
from typing import List, Dict, Optional, Union
# Type aliases: PascalCase
UserID = int
UserData = Dict[str, Union[str, int]]
UserList = List['User']
# Function with type hints
def get_user_by_id(user_id: UserID) -> Optional['User']:
"""Get user by ID with type hints."""
return database.query(user_id)
def process_users(users: UserList) -> None:
"""Process list of users."""
for user in users:
print(user.name)
# Variables with type hints
user_name: str = "John"
user_age: int = 25
is_active: bool = True
users: List[User] = []8. Exception Names
Exception classes should end with "Error" suffix and use PascalCase.
# ✅ Good
class ValidationError(Exception):
"""Raised when validation fails."""
pass
class DatabaseConnectionError(Exception):
"""Raised when database connection fails."""
pass
class UserNotFoundError(Exception):
"""Raised when user is not found."""
pass
# Usage
def get_user(user_id):
if user_id not in database:
raise UserNotFoundError(f"User {user_id} not found")
return database[user_id]
# ❌ Bad
class ValidationException(Exception): # Use Error suffix
pass
class user_not_found(Exception): # Use PascalCase
pass9. Naming Conventions Summary Table
| Type | Convention | Example |
|---|---|---|
| Variables | snake_case | user_name |
| Functions | snake_case | get_user_data() |
| Classes | PascalCase | UserAccount |
| Constants | UPPER_SNAKE_CASE | MAX_RETRY_COUNT |
| Protected | _snake_case | _internal_method |
| Private | __snake_case | __private_var |
| Modules | lowercase or snake_case | user_service.py |
10. Linting with Pylint/Flake8
Automatically enforce PEP 8 naming with linters:
# Install linters
pip install pylint flake8 black
# .pylintrc configuration
[BASIC]
good-names=i,j,k,_
bad-names=foo,bar,baz
function-rgx=[a-z_][a-z0-9_]{2,30}$
variable-rgx=[a-z_][a-z0-9_]{2,30}$
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Run linters
pylint myfile.py
flake8 myfile.py
black myfile.py # Auto-format11. Common Mistakes to Avoid
- ❌ Using camelCase:
getUserData() - ❌ Using PascalCase for functions:
GetUserData() - ❌ Using snake_case for classes:
user_account - ❌ Inconsistent casing:
get_UserData - ❌ Too short names:
uinstead ofuser - ❌ Not using underscores:
getuserdata
12. Best Practices
- Follow PEP 8: Use snake_case for functions/variables, PascalCase for classes
- Be descriptive:
calculate_total_price()overcalc() - Use verbs for functions:
get_user(),create_order(),validate_email() - Use nouns for classes:
User,Order,Database - Avoid abbreviations:
user_manageroverusr_mgr - Use type hints: Improves code clarity and catches errors early
Need to Convert Text?
Use our free converter to transform text to Python-style snake_case:
Conclusion
Python's PEP 8 naming conventions are clear and widely adopted: snake_case for functions and variables, PascalCase for classes, and UPPER_SNAKE_CASE for constants. Following these standards makes your code more Pythonic, easier to read, and better integrated with the Python ecosystem. Use linters like Pylint and Black to enforce conventions automatically.