Every program you write is going to involve storing and reusing values — a user's name, a running total, a list of results. That's what python variables are for. This article covers how variables actually work in Python, the naming rules the language enforces, and the PEP 8 naming conventions that separate code that merely runs from code that reads well.
What is a Variable in Python?
A variable is simply a name that references a value stored in memory. Instead of typing 42 repeatedly throughout your program, you give that value a name — age = 42 — and refer to age from then on.
No explicit declaration
Unlike some languages, Python doesn't require you to declare a variable before using it, and there's no keyword like var or let involved. Assignment itself is what creates the variable:
# This single line both creates and assigns the variable
x = 5That's the entire "declaration." Before this line runs, x doesn't exist. After it, x exists and holds the value 5.
Dynamic typing
Python is also dynamically typed, meaning you never declare a variable's type up front. The interpreter figures out the type based on the value assigned to it, and that type can even change later:
x = 5 # x is currently an integer
x = "hello" # now x is a string — Python doesn't complainThis flexibility is part of why Python is considered approachable for beginners — there's no type system ceremony standing between you and writing working code. It does mean you're responsible for keeping track of what a variable actually holds, especially in larger programs.
Python's Mandatory Naming Rules
Python enforces a few strict rules on variable names. Break these, and your code won't run — these aren't style suggestions, they're syntax requirements.
Must start with a letter or underscore
A variable name can't start with a digit:
age = 25 # valid
_age = 25 # valid
2age = 25 # invalid — SyntaxErrorOnly letters, numbers, and underscores
No spaces, hyphens, or other special characters are allowed anywhere in the name:
user_name = "Alex" # valid
user-name = "Alex" # invalid — Python reads the hyphen as subtraction
user name = "Alex" # invalid — spaces aren't allowed in namesCase sensitivity
Python treats different capitalization as entirely different variables. age and Age are two separate variables that happen to look similar:
age = 25
Age = 30
print(age) # 25
print(Age) # 30This trips up a lot of beginners — a typo in capitalization doesn't throw an error, it silently references (or creates) the wrong variable.
Can't use reserved keywords
Python reserves certain words for the language itself, and you can't use them as variable names — words like for, if, class, def, return, import, and others:
for = 5 # invalid — SyntaxError, 'for' is a reserved keywordIf you're ever unsure whether a word is reserved, Python's keyword module can tell you:
import keyword
print(keyword.iskeyword("class")) # TrueAvoid ambiguous single-character names
This one isn't enforced by the interpreter, but it's worth calling out early: avoid naming variables l (lowercase L), O (uppercase O), or I (uppercase I). Depending on the font, they're easy to confuse with the digits 1 and 0, or with each other. It's a small thing that causes real confusion in shared code.
PEP 8 Naming Conventions (Best Practices)
Beyond what Python requires, PEP 8 — the official Python style guide — lays out conventions that the vast majority of Python code follows. These aren't enforced by the interpreter, but ignoring them makes your code look immediately unfamiliar to other Python developers.
snake_case for variables and functions
Lowercase words separated by underscores is the standard for variables and function names:
user_name = "Alex"
total_price = 49.99
def calculate_total_price(price, tax_rate):
return price * (1 + tax_rate)PascalCase for class names
Classes use PascalCase (also called CamelCase) — each word capitalized, no underscores:
class UserProfile:
pass
class ShoppingCart:
passUPPER_SNAKE_CASE for constants
Values that shouldn't change during a program's execution are conventionally written in all caps with underscores. Python doesn't actually enforce immutability here — this is purely a signal to other developers ("don't reassign this"):
MAX_ATTEMPTS = 3
API_KEY = "your-key-here"Leading underscore conventions
A few underscore patterns carry specific meaning in Python:
_internal_var— a single leading underscore signals "this is intended for internal use," a soft convention meaning other code shouldn't rely on it directly, though nothing stops it from being accessed.__mangled— a double leading underscore inside a class triggers Python's name mangling, which actually changes how the attribute is stored internally, making accidental access from outside the class harder._— a single underscore by itself is the conventional "throwaway" variable name, used when you need to accept a value but don't actually plan to use it:
# We only care about the index, not the value
for _, value in enumerate(["a", "b", "c"]):
passWhy PEP 8 naming matters
Following these python naming conventions isn't about pleasing some abstract rulebook. It matters for three practical reasons: readability (anyone opening your code recognizes the patterns instantly), team collaboration (consistent naming reduces friction when multiple people work on the same codebase), and tooling compatibility (linters and formatters like Ruff and Pylint are built around PEP 8 and will flag deviations).
Writing Descriptive, Pythonic Variable Names
Following the formatting rules is only half the picture — the actual words you choose matter just as much.
Meaningful over vague
Compare these two function names:
def calc(p, t):
return p * (1 + t)
def calculate_total_price(price, tax_rate):
return price * (1 + tax_rate)Both do the same thing. Only one of them tells you what it does without needing to read the implementation. Vague names like calc, data, or temp save a few keystrokes now and cost real time later — for you, three weeks from now, and for anyone else reading the code.
Balancing brevity and clarity
That said, brevity isn't always wrong. Short loop counters like i, j, and k are a widely accepted exception, especially in simple, short-lived loops:
for i in range(10):
print(i)Using index_counter here wouldn't add any real clarity — it would just add noise. The rule of thumb: the shorter a variable's scope and lifetime, the more acceptable a short name becomes. A variable used across fifty lines of a function deserves a real name; a loop counter used across three lines doesn't need one.
Common naming mistakes beginners make
camelCase habits carried over from other languages. If you've written any JavaScript or Java,
userNamemight feel natural — but in Python, that'suser_name. Mixing conventions within the same codebase looks inconsistent and will get flagged by any linter following PEP 8.Overusing ALL_CAPS. Reserve UPPER_SNAKE_CASE strictly for genuine constants. Writing regular variables in all caps just to make them "feel important" defeats the purpose of the convention — it stops meaning anything once it's everywhere.
Enforcing Consistency: Tools & Quick Reference
Let tooling handle it
You don't need to manually police every name in your codebase. Formatters and linters catch a lot of this automatically:
Ruff and Pylint will flag names that don't follow PEP 8 conventions.
Black (or Ruff's formatting mode) won't rename your variables for you, but keeps the surrounding code consistent enough that naming inconsistencies stand out more clearly.
If you set up VS Code or PyCharm following the earlier articles in this series, you likely already have this tooling in place — turning on linting will start surfacing naming issues as you type.
Quick reference table
Type | Convention | Example |
|---|---|---|
Variable | snake_case |
|
Function | snake_case |
|
Class | PascalCase |
|
Constant | UPPER_SNAKE_CASE |
|
Internal/protected | leading underscore |
|
Name-mangled | double leading underscore |
|
Throwaway | single underscore |
|
Consistency over rigid rule-following
One last note: if you join an existing project or codebase that already uses a slightly different style, matching that project's existing conventions matters more than rigidly following PEP 8 to the letter. Consistency within a codebase is more valuable than perfect adherence to an external standard. PEP 8 is the right default when you're starting fresh — but it's a starting point, not a law.