Python Syntax
Every programming language has a set of rules that determine what counts as valid code — this is its syntax. Python’s syntax is famous for being clean and readable because it uses indentation instead of curly braces or keywords to mark blocks of code. Understanding these rules is the foundation for everything else you’ll write in Python: get the syntax wrong and your program won’t even start; get it right and Python reads almost like structured English.
Overview / How Python Syntax Works
Python source code is plain text, read top to bottom by the Python interpreter. Before your code runs, the interpreter performs several passes: it tokenizes the raw characters into meaningful pieces (keywords, identifiers, operators, literals), checks that those tokens form legal statements according to Python’s grammar, compiles the result into bytecode, and only then executes it. If your code violates the grammar rules — a missing colon, a mismatched indentation level, an unclosed bracket — the interpreter raises a SyntaxError during this compilation step, before a single line of your program actually runs.
The single most distinctive rule in Python’s syntax is that whitespace is meaningful. In languages like C, Java, or JavaScript, blocks of code are wrapped in curly braces { }, and indentation is just a cosmetic convention for humans. In Python, there are no curly braces for blocks at all — indentation is the block structure. When you write an if statement, a loop, a function, or a class, the header line ends with a colon (:), and every line that belongs to that block must be indented consistently underneath it. When the indentation decreases back to the level of the header, Python knows the block has ended.
Internally, Python’s tokenizer actually emits special INDENT and DEDENT tokens as it scans your source line by line, based on how far each line is indented compared to the one before it. Those tokens function exactly like opening and closing braces would in another language — they just happen to be generated from whitespace rather than typed by you. This is why consistent indentation isn’t a style preference in Python, it’s a hard requirement enforced by the language itself.
A Python program is made up of statements — instructions that do something, like an assignment, a function call, or a loop. Statements are normally separated by newlines (one statement per line), but Python also supports combining multiple simple statements on one line with semicolons, and splitting one long statement across multiple lines using line-continuation rules. All of this is governed by a small, learnable set of syntax rules covered below.
Syntax
The table below summarizes the core syntax rules every Python program follows.
| Rule | Description |
|---|---|
| Indentation | Defines code blocks. Use a consistent number of spaces (4 is the standard) for every line within the same block. |
Colon : |
Required at the end of a block header — if, for, while, def, class, try, with, etc. |
| Case sensitivity | Age, age, and AGE are three different identifiers in Python. |
| Comments | # starts a single-line comment; triple-quoted strings (""" ... """) are often used as multi-line docstrings/comments. |
| Line continuation | A backslash \ at the end of a line continues a statement onto the next line; expressions inside (), [], or {} continue automatically without a backslash. |
Semicolon ; |
Optional — separates multiple simple statements written on a single line. Rarely used; considered unpythonic in most cases. |
| Identifiers | Names for variables, functions, classes, etc. Must start with a letter or underscore, followed by letters, digits, or underscores. No spaces or hyphens. |
| Keywords | Reserved words like if, def, class, return, import cannot be used as identifiers. |
The general shape of any block-based statement looks like this:
header_keyword condition_or_target:
statement_1
statement_2
...
header_keyword— a keyword such asif,for,while,def, orclass.condition_or_target— an expression to evaluate, or a name being defined.:— mandatory; marks the start of the indented block.- indented lines — the body of the block, all indented by the same amount.
Examples
Example 1: Indentation defines the block
age = 20
if age >= 18:
print("You are an adult.")
print("You can vote.")
else:
print("You are a minor.")
print("You cannot vote yet.")
Output:
You are an adult.
You can vote.
Both print() calls under if age >= 18: are indented by four spaces, so Python treats them as one block belonging to that condition. Because age is 20, the condition is true, so only the two lines under if run — the else block is skipped entirely. If the second print() line were indented by a different amount than the first, Python would raise an IndentationError rather than guess what you meant.
Example 2: Semicolons and line continuation
a = 5; b = 10; c = a + b
print(c)
total = (1 + 2 + 3 +
4 + 5 + 6)
print(total)
long_string = "This is a long string " \
"that continues on the next line."
print(long_string)
Output:
15
21
This is a long string that continues on the next line.
The first line packs three simple statements onto one physical line using semicolons — legal, but rarely used in real Python code because it hurts readability. The second block shows implicit line continuation: because the expression is wrapped in parentheses, Python knows the statement isn’t finished until the closing ), so it can safely span multiple lines with no backslash needed. The third block shows explicit line continuation with a trailing backslash \, which tells Python “this statement keeps going on the next line” — here it’s used to join two adjacent string literals into one.
Example 3: A realistic function with nested blocks
def classify_numbers(numbers: list[int]) -> dict[str, list[int]]:
"""Split numbers into even and odd groups."""
result = {"even": [], "odd": []}
for n in numbers:
if n % 2 == 0:
result["even"].append(n)
else:
result["odd"].append(n)
return result
data = [1, 2, 3, 4, 5, 6]
groups = classify_numbers(data)
print(groups)
Output:
{'even': [2, 4, 6], 'odd': [1, 3, 5]}
Notice the nested indentation: the function body is indented once (four spaces) under def, the for loop body is indented again under the for line, and the if/else bodies are indented a third time under those. Each level of nesting adds another four spaces. The triple-quoted string right after the def line is a docstring — Python treats it as the function’s documentation rather than executable code, and tools like help() can read it back.
Under the Hood: How Indentation Becomes Structure
When Python compiles a file, it doesn’t just look at spaces visually — it counts them precisely. Here’s what happens step by step:
- The tokenizer reads each line and measures its leading whitespace.
- If a line is indented further than the previous logical line, Python emits an
INDENTtoken — this can only legally happen right after a line ending in:. - If a line returns to a shallower indentation level, Python emits one or more
DEDENTtokens to close the blocks that just ended. - If the indentation of a line doesn’t match any previously opened block level exactly, Python raises an
IndentationErrorbecause it can’t tell which block you intended to close. - Once tokenized, the parser matches these
INDENT/DEDENTtokens against the grammar the same way it would match{/}in another language, building a tree structure that the compiler turns into bytecode.
This is also why mixing tabs and spaces is dangerous: your editor might display a tab as the same width as four spaces, so two lines can look identically indented while actually containing different bytes. Python 3 detects this ambiguity and refuses to guess — it raises a TabError rather than risk silently misinterpreting your block structure.
Common Mistakes
Mistake 1: Inconsistent indentation within a block
Mixing indentation widths for lines that are supposed to be in the same block is one of the most common beginner errors:
if age >= 18:
print("Adult")
print("Can vote")
The second print() is indented by three spaces instead of four, so Python cannot tell whether it belongs to the same block as the first line. This raises IndentationError: unindent does not match any outer indentation level. The fix is to make every line in the block use the exact same indentation — ideally by configuring your editor to insert 4 spaces per tab press, and never hand-mixing tabs and spaces.
Mistake 2: Forgetting the colon
if age >= 18
print("Adult")
Leaving off the trailing : after the condition produces SyntaxError: expected ':'. Every block header in Python — if, elif, else, for, while, def, class, try, except, finally, with — needs that colon. The corrected version simply adds it back: if age >= 18:.
Best Practices
- Use 4 spaces per indentation level — this is the PEP 8 standard and what nearly all Python code (and tooling) expects.
- Never mix tabs and spaces in the same file; configure your editor to convert tabs to spaces automatically.
- Avoid semicolons to pack multiple statements on one line — one statement per line is far more readable and easier to debug.
- Keep lines under about 79–99 characters; use parentheses for implicit line continuation rather than trailing backslashes whenever possible, since it’s less error-prone (a stray space after a backslash breaks it).
- Use descriptive,
snake_casenames for variables and functions, andPascalCasefor class names — this is a naming convention, not a hard syntax rule, but it’s near-universal in Python code. - Use a linter or your editor’s built-in Python support to catch indentation and syntax issues before you run the code.
- Write a short docstring under every function or class definition — it costs one indented triple-quoted string and pays off every time someone (including future you) reads the code.
Practice Exercises
- Exercise 1: Write an
if/elif/elsechain that takes a variablescoreand prints"Pass"if it’s 60 or above,"Borderline"if it’s between 50 and 59 inclusive, and"Fail"otherwise. Pay close attention to keeping each block’s indentation consistent. - Exercise 2: Rewrite the following single line, which uses semicolons to chain three statements, as three separate, properly formatted lines:
x = 3; y = 4; print(x + y). - Exercise 3: Write a long arithmetic expression (adding at least six numbers) that spans three lines using implicit line continuation inside parentheses, and print the result. Then rewrite it using an explicit backslash continuation instead, and confirm the output is identical.
Summary
- Python uses indentation, not braces, to define code blocks — consistency within a block is mandatory, not stylistic.
- Block headers (
if,for,while,def,class, etc.) always end with a colon:. - The tokenizer converts indentation changes into
INDENT/DEDENTtokens internally, which the parser uses just like braces in other languages. - Semicolons can separate multiple statements on one line but are rarely used idiomatically.
- Long statements can continue across lines implicitly inside
(),[],{}, or explicitly with a trailing backslash\. - Mismatched indentation raises
IndentationError; missing colons raiseSyntaxError; mixed tabs and spaces raiseTabError. - Following PEP 8 conventions (4-space indentation, no tab/space mixing, minimal semicolons) keeps your code both syntactically safe and easy for others to read.
