Python Variable Names — Rules, Conventions, and Best Practices
Learn Python variable naming rules, PEP 8 conventions, reserved keywords, and common pitfalls — with runnable examples and clear explanations.
A variable name is the label Python uses to find a value in memory. Choose good names and your code reads almost like a sentence; choose poor ones and even you will struggle to understand your own script a week later. This chapter covers the hard rules Python enforces, the soft conventions the community follows (PEP 8), gotchas like shadowing built-ins, and special underscore patterns — all with runnable examples.
Hard Rules — What Python Requires
Before conventions, there are rules. Breaking any of them is a SyntaxError or NameError.
Allowed characters
A variable name may contain letters (a-z, A-Z), digits (0-9), and underscores (_). It must start with a letter or an underscore — never a digit. No spaces, hyphens, or special characters (%, #, @, -) are allowed.
# Valid names
user_name = "Alice"
_private = 42
value1 = 3.14
MAX_RETRIES = 5
# Invalid names — these all raise SyntaxError
# 1user = "bad" # starts with a digit
# user-name = "bad" # hyphens are subtraction
# user name = "bad" # space is not allowedPython is case-sensitive
username, Username, and USERNAME are three completely different variables. This is a frequent source of bugs for beginners.
score = 10
Score = 20
SCORE = 30
print(score) # 10
print(Score) # 20
print(SCORE) # 30Reserved keywords cannot be used as names
Python reserves certain words for the language itself. Using one as a variable name raises a SyntaxError. You can list all reserved keywords with the keyword module:
import keyword
print(keyword.kwlist)Output (Python 3.12):
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await',
'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except',
'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is',
'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try',
'while', 'with', 'yield']Common mistakes: using list, str, int, type, or input as variable names — these are built-in names, not reserved keywords, so Python won't raise a SyntaxError, but you'll silently shadow the built-in and get confusing errors later (see Shadowing Built-ins below).
PEP 8 Naming Conventions
PEP 8 is Python's official style guide. Following it makes your code immediately readable to any Python developer.
Convention summary
| What you are naming | Convention | Example |
|---|---|---|
| Variable or function | snake_case | user_age, get_total() |
| Constant | ALL_CAPS_SNAKE | MAX_RETRIES, PI |
| Class | CapWords (PascalCase) | UserProfile, HttpError |
| Module / package | lowercase or snake_case | utils, data_parser |
| "Private" attribute | _single_leading_underscore | _cache, _helper() |
| Name-mangled attribute | __double_leading_underscore | __secret |
| Special dunder | __double_both_sides__ | __init__, __str__ |
snake_case for variables and functions
snake_case uses all lowercase letters with underscores between words. This is the standard for variables and functions in Python.
# PEP 8 compliant
first_name = "Alice"
last_name = "Smith"
total_price = 9.99
items_in_cart = 3
# Not PEP 8 (camelCase) — works, but avoid for variables
firstName = "Alice" # JavaScript style, not PythonicALL_CAPS for constants
By convention, a name written in all-uppercase letters signals "this value should not be changed". Python does not enforce immutability, but the convention is universally understood.
MAX_CONNECTIONS = 100
TIMEOUT_SECONDS = 30
PI = 3.141592653589793
# Using the constant
if current_connections > MAX_CONNECTIONS:
print("Connection limit reached")CapWords for classes
Class names use CapWords (also called PascalCase): each word starts with an uppercase letter, no underscores.
class UserProfile:
pass
class HttpRequestError(Exception):
passDescriptive and Meaningful Names
The best variable name tells the next reader what the value represents, not how it is stored. Aim for names that make a line of code read like a sentence.
# Unclear
r = 5
a = 3.14159 * r ** 2
# Clear
radius = 5
circle_area = 3.14159 * radius ** 2
print(circle_area) # 78.53975When short names are fine
Single-letter names (x, y, i, n) are acceptable in narrow, well-understood contexts:
- Loop counters:
for i in range(10): - Mathematical formulas:
y = m * x + b - Coordinates:
(x, y)or(row, col)
Outside these contexts, prefer something descriptive even if it is longer.
Avoid unnecessary abbreviations
Abbreviations save keystrokes but cost readability. Use full words unless the abbreviation is universally known.
# Unclear abbreviations
usr_nm = "alice"
tot_amt = 49.95
n_itm = 7
# Clear full names
username = "alice"
total_amount = 49.95
number_of_items = 7Widely accepted abbreviations that are fine to keep: url, id, http, db, idx, num.
Underscore Patterns
Python uses underscores in variable names to communicate intent. Understanding these patterns helps you read any Python codebase.
_single_leading — internal use
A name starting with one underscore is a signal to other developers: "this is an implementation detail; don't rely on it from outside this module or class." Python does not enforce this — it is purely a convention.
class DataLoader:
def __init__(self, path):
self.path = path
self._cache = {} # internal; not part of the public API
def load(self):
if self.path not in self._cache:
self._cache[self.path] = self._read_file()
return self._cache[self.path]
def _read_file(self):
# "private" helper
with open(self.path) as f:
return f.read()from module import * also skips names that start with _.
__double_leading — name mangling
Two leading underscores trigger Python's name mangling: __attr inside class Foo is stored as _Foo__attr. This prevents accidental overwriting in subclasses.
class Base:
def __init__(self):
self.__secret = "hidden"
obj = Base()
# print(obj.__secret) # AttributeError
print(obj._Base__secret) # "hidden" — mangled nameUse name mangling sparingly; it makes debugging harder.
__dunder__ — special methods
Names surrounded by double underscores on both sides are Python's built-in special ("dunder") methods and attributes. Never invent your own __name__ variables — Python reserves this namespace.
class Point:
def __init__(self, x, y): # called when an instance is created
self.x = x
self.y = y
def __repr__(self): # called by repr() and in the REPL
return f"Point({self.x}, {self.y})"
p = Point(3, 4)
print(p) # Point(3, 4)
print(repr(p)) # Point(3, 4)_ as a throwaway
A lone underscore _ is used by convention as a "don't care" variable when you must capture a value but won't use it.
# Unpack a tuple but only use two of three values
x, _, z = (1, 2, 3)
print(x, z) # 1 3
# Loop counter when the index is not needed
for _ in range(5):
print("hello")Shadowing Built-ins
Python's built-in names (list, str, int, dict, type, input, print, id, min, max, sum, open, …) are not keywords, so Python silently lets you reuse them as variable names. This is almost always a bug.
# Dangerous — shadows the built-in list type
list = [1, 2, 3]
print(list) # [1, 2, 3] — seems fine
new = list([4, 5]) # TypeError: 'list' object is not callableOnce you assign list = [1, 2, 3], the name list in that scope no longer refers to the built-in constructor. The fix is simply to choose a different name.
# Safe
numbers = [1, 2, 3]
more_numbers = list([4, 5]) # list() still works
print(more_numbers) # [4, 5]Common built-ins that are accidentally shadowed: id, input, type, str, int, float, list, dict, set, tuple, min, max, sum, filter, map, open, print.
Scope and Variable Names
A variable's name is only visible within the scope where it is defined. Two variables in different scopes can share the same name without conflict — but this can lead to confusion.
total = 0 # module-level variable
def calculate(prices):
total = 0 # local variable — does NOT overwrite the module-level one
for price in prices:
total += price
return total
result = calculate([10, 20, 30])
print(result) # 60
print(total) # 0 — unchangedFor more on how Python resolves names (the LEGB rule), see Python Scope. To understand global variables and the global keyword, see Global Variables in Python.
Quick Reference
# Hard rules
user1 = "ok" # letters, digits, underscores — fine
_private = "ok" # leading underscore — fine
# 1user = "bad" # SyntaxError: starts with digit
# my-var = "bad" # SyntaxError: hyphens not allowed
# PEP 8 conventions
snake_case_var = 42 # variables and functions
MAX_VALUE = 100 # constants
# class names use CapWords (PascalCase)
# Underscore patterns
_internal = "internal use" # single leading: hint "private"
_ = "throwaway" # lone underscore: discard value
# What to avoid
# list = [] # shadows built-in
# str = "hello" # shadows built-in
# if = True # SyntaxError: reserved keywordFor a broader introduction to how variables are created and assigned in Python, see Python Variables. For how to group related variables together, see Group Variables in Python.