PythonPython Syntax & Indentation

Python Syntax & Indentation

Every programming language needs a way to say "this group of statements belongs together." Languages like C, Java, and JavaScript wrap those groups in curly braces: a backtrace-style block like if (x) { doThing(); doOtherThing(); }. Python takes a completely different approach — it uses indentation itself to define blocks. There are no braces to open or close. The whitespace at the start of a line is not just cosmetic; it is part of the language's grammar.

Indentation instead of braces

In brace-based languages, indentation is a courtesy to human readers — the compiler does not care whether you indent at all. You could write an entire program on one line (ignoring style guides and your teammates' patience) and it would still run. Python removes that option entirely. The interpreter uses indentation to know where a block of code starts and ends, so consistent whitespace is not a style preference — it is required syntax.

Python
def greet(name):
    if name:
        print(f"Hello, {name}!")
    else:
        print("Hello, stranger!")

greet("Ava")
greet("")
Hello, Ava!
Hello, stranger!

Notice that there are no braces anywhere in that function. The body of greet is everything indented one level under the def line; the body of the if is everything indented one level further under it. Remove the indentation and the interpreter has no way to know what belongs to what — which is exactly the point.

Why Python chose this design

This wasn't an accident or a shortcut — it was a deliberate design decision by Python's creator, Guido van Rossum, aimed squarely at readability. Python's guiding philosophy, "The Zen of Python" (try running import this in a Python shell), includes the line "Readability counts." By making indentation mandatory rather than optional, Python forces every piece of code — yours, a coworker's, code from a tutorial you found ten years ago — to look visually consistent by construction. You can't hide a messy, inconsistently-indented block behind a pair of braces on one line, because there are no braces to hide behind.

The practical benefit is that Python code tends to look the way it behaves. In brace languages, misleading indentation (code that's indented as if it's inside a block, but the braces say otherwise) is a genuine, well-documented source of bugs — famously the root cause of Apple's "goto fail" SSL bug. Python sidesteps that entire bug class: if the indentation looks right, it is right, because indentation is the mechanism, not just the appearance.

Aspect

Brace-based languages (C, Java, JS)

Python

Block delimiters

Curly braces { }

Indentation level

Indentation enforced?

No — purely cosmetic

Yes — it is the syntax

Misleading indentation possible?

Yes (braces can disagree with indentation)

No (indentation cannot disagree with itself)

Empty block

{}

pass keyword required

The 4-space rule (PEP 8)

Python doesn't mandate an exact number of spaces at the language level — technically any consistent amount works. But the community style guide, PEP 8, standardizes on 4 spaces per indentation level, and virtually every code base, linter, and formatter (including black) enforces it. Sticking to 4 spaces means your code will look the same in any editor, on any team, in any tutorial — which is the entire point of a shared convention.

Python
class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance

    def deposit(self, amount):
        if amount > 0:
            self.balance += amount
        return self.balance
  • Use 4 spaces per indentation level — never a single space, never 2, never 8.

  • Each nested block (a body inside an if, for, def, class, etc.) adds one more 4-space level.

  • Configure your editor to insert spaces (not a tab character) whenever you press the Tab key.

What happens when indentation is wrong: IndentationError

Because indentation carries real meaning, getting it wrong isn't a style nitpick — it's a syntax error the interpreter refuses to run past. The most common case is inconsistent indentation within the same block: two lines that are supposed to be siblings (same block) but are indented by different amounts.

Python
def check_temperature(temp):
    if temp > 30:
        print("It's hot outside")
       print("Stay hydrated")
    else:
        print("Comfortable weather")

Look closely at the third line: print("Stay hydrated") is indented with 7 spaces while the line above it uses 8. They are meant to be two statements in the same if block, but their indentation disagrees. Running this file produces an immediate error — the program never even starts executing:

  File "temperature.py", line 4
    print("Stay hydrated")
                          ^
IndentationError: unindent does not match any outer indentation level

Python is telling you, quite literally, that it tried to match line 4's indentation to some enclosing block it already knows about, and couldn't. The fix is simply to make every statement in the same block share the exact same indentation:

Python
def check_temperature(temp):
    if temp > 30:
        print("It's hot outside")
        print("Stay hydrated")
    else:
        print("Comfortable weather")
It's hot outside
Stay hydrated
Note
Other common variants of this error include `IndentationError: expected an indented block` (you wrote a colon-terminated line like `if x:` but the next line isn't indented at all) and `IndentationError: unexpected indent` (a line is indented when nothing about the previous line called for a new block).
Tabs vs. spaces: a classic trap

Tab characters and space characters can look identical in most editors — that's exactly what makes mixing them dangerous. A block that looks perfectly aligned on your screen might actually contain a mix of tabs and spaces that a different editor (or a different tab-width setting) renders completely differently. Python 3 defends against this by disallowing indentation that mixes tabs and spaces in a way it considers ambiguous, and raises a TabError rather than guessing what you meant.

Python
def show_total(items):
    total = 0
    for item in items:
	total += item
    return total
  File "totals.py", line 4
    total += item
             ^
TabError: inconsistent use of tabs and spaces in indentation

In that example, the for loop's body was typed with a literal tab character while every surrounding line uses spaces. It may well have looked "aligned" in the editor that wrote it, but Python refuses to guess whether that tab means "4 spaces," "8 spaces," or something else — so it fails loudly instead of silently misinterpreting your block structure.

Warning
Never mix tabs and spaces in the same Python file, and especially never within the same block. Configure your editor so the Tab key inserts spaces (most editors call this "insert spaces for tabs" or "soft tabs"), and set the tab width to 4. This single setting eliminates one of the most notorious "it works on my machine" bugs in Python — code that looks fine in your editor but throws a `TabError` (or worse, silently runs the wrong block) for a teammate using a different editor.
Line continuation: splitting statements across lines

Since indentation is meaningful, Python needs an unambiguous way to let a single logical statement span multiple physical lines without that being mistaken for a new block. There are two mechanisms: implicit continuation inside brackets, and explicit continuation with a backslash.

Implicit continuation happens automatically whenever an expression is inside parentheses (), square brackets [], or curly braces {}. Python knows the statement isn't finished until the brackets are balanced, so you can freely break lines — and indent for readability — without any special punctuation. This is the preferred style because it's robust: it can't be broken by an invisible trailing character.

Python
total = (
    price_of_apples
    + price_of_bananas
    + price_of_oranges
)

shopping_list = [
    "milk",
    "eggs",
    "bread",
]

result = some_function(
    first_argument,
    second_argument,
    keyword_argument=42,
)

Explicit continuation uses a trailing backslash (\) at the very end of a line to tell Python "this statement keeps going on the next line." It works outside of brackets, but it's fragile: the backslash must be the absolute last character on the line — even one trailing space after it silently breaks the continuation (or causes a syntax error) — and it's easy to overlook when skimming code. Most style guides, including PEP 8, recommend preferring implicit (bracket) continuation whenever possible and reserving the backslash for the rare case where brackets aren't natural, such as chaining a long boolean expression.

Python
is_valid = first_condition \
    and second_condition \
    and third_condition

Continuation style

Syntax

Robustness

Implicit (inside brackets)

Line break anywhere inside (), [], {}

Preferred — no invisible characters to get wrong

Explicit (backslash)

Trailing \ at end of line

Fragile — a stray trailing space breaks it

Tip
When a line of code gets too long, first ask whether it can be wrapped in parentheses instead of reaching for a backslash — even a single extra pair of parens around an expression is enough to enable implicit continuation.
Semicolons: allowed, but discouraged

Unlike C, Java, or JavaScript, Python does not require a semicolon to end a statement — the end of a line is enough. Semicolons are still legal in Python, but their only real use is to place multiple statements on a single physical line, separating each one:

Python
x = 1; y = 2; z = x + y
print(z)
3

This works, but it goes against Python's own style conventions. PEP 8 explicitly discourages putting multiple statements on one line with semicolons, because it undercuts the same readability goal that motivated significant indentation in the first place — a reviewer scanning down the left edge of the file for structure will miss a statement hiding after a semicolon. The idiomatic version simply puts each statement on its own line:

Python
x = 1
y = 2
z = x + y
print(z)
Note
You'll occasionally see semicolons used deliberately in one-off scripts or interactive sessions to save vertical space, but in any code meant to be read or maintained by others, treat the semicolon as something Python allows rather than something Python wants you to use.