Python Naming Conventions
Naming things is one of the hardest parts of programming, but Python makes it easier by having clear, well-established conventions. Following these conventions makes your code instantly recognizable to other Python developers.
Why Naming Conventions Matter
Consistent naming tells readers what kind of thing they're looking at — a variable, a class, a constant — without needing to check the definition. PEP 8, Python's official style guide, codifies these conventions so the entire ecosystem speaks the same language.
snake_case for Variables, Functions, Methods, and Modules
The most common naming style in Python is snake_case — all lowercase with words separated by underscores:
# Variables
user_name = "Alice"
total_count = 42
is_active = True
# Functions
def calculate_total(price, tax_rate):
return price * (1 + tax_rate)
# Methods
class ShoppingCart:
def add_item(self, item):
self.items.append(item)
def get_total_price(self):
return sum(item.price for item in self.items)
# Modules (file names)
# my_module.py
# database_utils.py
# test_helpers.py
Click "Run" to execute your codeUpperCamelCase (PascalCase) for Classes
Class names use UpperCamelCase, where each word starts with a capital letter and there are no underscores:
class HttpClient:
pass
class DatabaseConnection:
pass
class UserAuthenticationManager:
pass
This convention applies to all classes, including those in inheritance hierarchies and polymorphic base classes. When you see a CamelCase name, you immediately know it's a class — even if it's an abstract base class or a mixin:
from abc import ABC, abstractmethod
class Shape(ABC):
"""Base class for all shapes (polymorphic base)."""
@abstractmethod
def area(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
Click "Run" to execute your codeUPPER_SNAKE_CASE for Constants
Constants — values that shouldn't change — use all uppercase with underscores:
MAX_CONNECTIONS = 100
DEFAULT_TIMEOUT = 30
PI = 3.14159265358979
DATABASE_URL = "postgresql://localhost/mydb"
HTTP_STATUS_OK = 200
Note: Python doesn't enforce immutability for constants.
UPPER_SNAKE_CASEis a signal to other developers: "don't reassign this." It's a social contract, not a language feature.
_single_leading_underscore for Internal Use
A single leading underscore signals "this is for internal use" — it's a convention, not enforcement:
class BankAccount:
def __init__(self, balance):
self._balance = balance # Internal — use the property instead
@property
def balance(self):
return self._balance
def _validate_amount(self, amount):
"""Internal helper — not part of the public API."""
if amount <= 0:
raise ValueError("Amount must be positive")
When you do from module import *, names starting with _ are not imported. This is the one case where the underscore has a real effect beyond convention.
__double_leading_underscore for Name Mangling
Double leading underscores trigger Python's name mangling mechanism. The interpreter rewrites the attribute name to include the class name, which prevents accidental overrides in subclasses:
class Base:
def __init__(self):
self.__secret = "base secret" # Becomes _Base__secret
class Child(Base):
def __init__(self):
super().__init__()
self.__secret = "child secret" # Becomes _Child__secret
Name mangling is specifically designed for inheritance hierarchies. When a subclass defines __secret, it doesn't collide with the parent's __secret because Python renames them differently based on the class they're defined in. This interacts with the Method Resolution Order (MRO) — the mangled name is determined by the class where the attribute is defined, not where it's accessed:
class Base:
def __init__(self):
self.__value = 10 # Stored as _Base__value
def get_value(self):
return self.__value # Accesses _Base__value
class Child(Base):
def __init__(self):
super().__init__()
self.__value = 20 # Stored as _Child__value
def get_child_value(self):
return self.__value # Accesses _Child__value
Click "Run" to execute your codeWhen to use it: Rarely. Most of the time, a single underscore (
_name) is enough. Use double underscores only when you specifically need to avoid name collisions in complex inheritance hierarchies.
__dunder__ Methods (Magic Methods)
Names with double leading and trailing underscores are "dunder" (double underscore) methods — also called magic methods or special methods. These are reserved by Python and define how objects behave with built-in operations:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Vector({self.x}, {self.y})"
def __str__(self):
return f"({self.x}, {self.y})"
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __len__(self):
return 2
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
These dunder methods are the backbone of polymorphism in Python. When you call len(obj), Python calls obj.__len__(). When you use ==, it calls __eq__(). This means any class can participate in Python's built-in protocols simply by implementing the right dunder methods:
| Dunder Method | Triggered By | Purpose |
|---|---|---|
__init__ |
MyClass() |
Initialize a new instance |
__str__ |
str(obj), print(obj) |
Human-readable string |
__repr__ |
repr(obj), REPL display |
Developer-readable string |
__eq__ |
a == b |
Equality comparison |
__len__ |
len(obj) |
Length of container |
__iter__ |
for x in obj |
Make object iterable |
__getitem__ |
obj[key] |
Bracket access |
__add__ |
a + b |
Addition operator |
__contains__ |
x in obj |
Membership test |
Click "Run" to execute your codeImportant: Never invent your own dunder names like
__mymethod__. These are reserved for Python itself. If you need a private method, use_mymethodinstead.
Why Python Chose snake_case
Python's choice of snake_case has roots in its core philosophy: readability counts (from the Zen of Python). Guido van Rossum formalized this in PEP 8 back in 2001, but the convention predates the PEP.
The reasoning:
calculate_total_priceis more readable thancalculateTotalPriceat a glance- Underscores create visual separation between words
- Consistency with the standard library (which uses
snake_casealmost everywhere) - Python values explicit readability over saving a few keystrokes
This contrasts with languages like Java and JavaScript, which prefer camelCase. Neither is objectively better — it's about consistency within the ecosystem.
Naming Convention Quick Reference
| What | Convention | Example |
|---|---|---|
| Variable | snake_case |
user_count |
| Function | snake_case |
get_user() |
| Method | snake_case |
obj.calculate_total() |
| Module (file) | snake_case |
my_module.py |
| Package (folder) | snake_case |
my_package/ |
| Class | UpperCamelCase |
HttpClient |
| Exception | UpperCamelCase + Error |
ValueError |
| Constant | UPPER_SNAKE_CASE |
MAX_RETRIES |
| Internal | _leading_underscore |
_helper() |
| Name-mangled | __double_leading |
__private_attr |
| Magic method | __dunder__ |
__init__() |
| Type variable | UpperCamelCase (short) |
T, KT, VT |
Naming in Class Hierarchies
When building class hierarchies, naming conventions help signal the intent of each class. This becomes especially important with multiple inheritance and mixins.
Base Classes
Base classes are typically named as plain nouns describing the concept:
class Animal:
"""Concrete or abstract base for all animals."""
pass
class Vehicle:
"""Base class for all vehicle types."""
pass
Abstract Classes
Prefix or suffix to signal that the class shouldn't be instantiated directly. Python developers commonly use Abstract as a prefix or Base as a suffix:
from abc import ABC, abstractmethod
class AbstractProcessor(ABC):
"""Must be subclassed — cannot be used directly."""
@abstractmethod
def process(self, data):
pass
class BaseHandler:
"""Provides shared logic; subclass to customize."""
def handle(self, request):
self.pre_handle(request)
result = self.do_handle(request)
self.post_handle(request)
return result
Mixins
Mixins are small classes designed to be combined with other classes via multiple inheritance. Name them with a Mixin suffix so their purpose is immediately clear:
class LoggingMixin:
"""Add logging capability to any class."""
def log(self, message):
print(f"[{self.__class__.__name__}] {message}")
class SerializableMixin:
"""Add JSON serialization to any class."""
def to_dict(self):
return self.__dict__.copy()
class ApiClient(LoggingMixin, SerializableMixin):
def __init__(self, base_url):
self.base_url = base_url
def fetch(self, endpoint):
self.log(f"Fetching {endpoint}")
return {"url": f"{self.base_url}/{endpoint}"}
When using multiple inheritance, Python follows the Method Resolution Order (MRO) — a linearization of the class hierarchy using the C3 algorithm. The MRO determines which method gets called when multiple parent classes define the same method. You can inspect it with ClassName.__mro__ or ClassName.mro():
Click "Run" to execute your codeNaming Conventions Signal Intent
Good naming in a class hierarchy tells the reader:
Animal— this might be a concrete class or an abstract baseAbstractAnimal— definitely abstract, must subclassAnimalBase— provides shared functionality, probably meant to be subclassedFlyingMixin— a mixin, designed for multiple inheritanceIAnimal— interface style (less common in Python, more Java/C#)
Tip: In Python, prefer
AbstractXorXBasefor abstract classes andXMixinfor mixins. Avoid theIXinterface prefix — it's not Pythonic.
Common Mistakes
A few naming pitfalls to avoid:
- Single-letter names (except in loops or math):
x = get_user()tells you nothing - Abbreviations:
calc_ttl_prcis harder to read thancalculate_total_price - Misleading names:
user_listthat's actually a dict,is_validthat returns a string - Shadowing built-ins: don't name variables
list,dict,type,id,input, orstr
# Bad — shadows the built-in
list = [1, 2, 3] # Now you can't use list() anywhere
type = "admin" # Now you can't use type() anywhere
# Good — be more specific
user_list = [1, 2, 3]
user_type = "admin"