Dataslope logoDataslope

Syntax and Indentation

How Python uses whitespace, PEP 8 style, and the tabs vs spaces convention

The previous page noted that Python uses indentation to delimit blocks of code. This page goes into detail: what counts as a block, what PEP 8 has to say about style, how to keep your editor honest, and why this choice sparked one of programming's most famous debates.

Why Python chose significant whitespace

Most languages in the 1980s and 1990s used braces ({ ... }) or keywords (begin ... end) to mark blocks. Python took a different path: Guido van Rossum observed that programmers already indent code to show structure to humans, so why not make the compiler trust that indentation? The result is that:

  1. Badly indented code will not run. A misaligned line is a syntax error, not a silent bug.
  2. Every Python codebase looks consistent. There is no "my braces on the same line" vs "my braces on the next line" religious war.
  3. Beginner-friendly. New programmers do not have to learn a special punctuation syntax; they just indent naturally.

This design choice is polarizing. Some find it liberating; others miss the explicit delimiters of C-like languages. Either way, it is non-negotiable in Python.

Blocks are indentation

In C, JavaScript, or Java, code inside a function or if is wrapped in { ... }. In Python it is wrapped in a deeper indentation level:

Code Block
Python 3.13.2

The colon (:) at the end of def, if, for, while, try, class, and so on signals "the next indented block belongs to me".

Think of the colon as Python's way of saying "here comes a block". It replaces the opening brace { in C-like languages. The dedent (returning to the previous indentation level) implicitly closes the block.

What happens when indentation is wrong

If indentation is missing where Python expects it, you get an IndentationError. If it is inconsistent, you get a TabError or a silently broken program (in older Python 2 codebases).

Code Block
Python 3.13.2

Mixing tabs and spaces

Python 3 will raise a TabError if a single block mixes tabs and spaces. Python 2 allowed it and silently treated a tab as "however many spaces it takes to reach the next multiple of 8", which caused famously confusing bugs. Configure your editor to insert spaces when you press the Tab key, and you will never see this error.

The four-space rule (PEP 8)

PEP 8, Python's official style guide, says:

  • Use four spaces per indentation level.
  • Do not mix tabs and spaces inside the same block. Python 3 raises a TabError if you try.
  • Limit lines to 79 characters (or 99 in modern codebases that follow black's default of 88).
  • Two blank lines between top-level functions and classes; one blank line between methods inside a class.
  • One statement per line. if x: do(); other() is legal but frowned upon.

Tools that enforce this for you:

  • black reformats your code in one consistent style with almost no configuration. It is the most popular Python formatter.
  • ruff is a very fast linter that rolls up most of the older tools (flake8, isort, pyupgrade).
  • Most editors (VS Code, PyCharm, Vim, Emacs) can run these on save.

The tabs vs spaces debate

We touched on this on the Python History page. The debate is older than Python itself and predates programming languages: it started with typewriters and word processors. The arguments in favor of each:

ArgumentTabsSpaces
Each developer picks their own width✅ Yes❌ No
Renders identically everywhere❌ No✅ Yes
Easier to align continuation lines❌ No✅ Yes
Default in PEP 8, black, ruff❌ No✅ Yes
Allowed in Python 3 source✅ Yes (alone)✅ Yes (alone)
Accessibility: screen readers / low vision✅ Better❌ Worse

The strongest argument for tabs

The accessibility argument is real: a developer with low vision can configure their editor to display a tab as 8 spaces for easier reading, while a sighted colleague can set it to 2 spaces to fit more code on screen. With spaces, everyone is locked into the same visual width.

The strongest argument for spaces

Tabs break alignment of continuation lines. Consider:

result = some_function(arg1, arg2,
                       arg3, arg4)

If the file uses tabs, the alignment of arg3 depends on the tab width of your editor. On one machine it looks perfect; on another it is misaligned. Spaces render identically everywhere.

The community consensus

The community has effectively settled on four spaces. PEP 8 states:

Spaces are the preferred indentation method. Tabs should be used solely to remain consistent with code that is already indented with tabs.

For brand-new code, use four spaces. If you join a project that already uses tabs, stay consistent with what is there. Either way, configure your editor to insert one or the other automatically so you never produce mixed indentation.

The Silicon Valley incident

In the TV show Silicon Valley, an engineer quits over a tabs-vs-spaces argument. The scene is a joke, but it is rooted in reality: this debate has genuinely derailed code reviews and project contributions. Do not let it derail yours. Pick four spaces and move on.

Continuation lines

Python statements normally end at the end of a line. There are two ways to span multiple lines:

  1. Implicit continuation inside (), [], or {}. This is the preferred style.
  2. Explicit continuation with a backslash \ at end of line.
Code Block
Python 3.13.2
Code Block
Python 3.13.2

PEP 8 recommends avoiding backslash continuation where possible. Modern code wraps long lines in parentheses even when they are not strictly needed (e.g. for a long if condition).

Semicolons (please do not)

Python technically allows ; to separate statements on one line. The community consensus is do not use it. PEP 8 says "avoid it" in polite language; the real sentiment is "never do this".

Code Block
Python 3.13.2

The only exception is in one-liners passed to python -c:

python -c "import sys; print(sys.version)"

Even there, most people avoid ; and use newlines instead.

Real-world comparison: Python vs other languages

Here is how other popular languages handle indentation:

LanguageBlock delimiterIndentationCommunity standard
PythonIndentationRequired4 spaces (PEP 8)
JavaScript{ ... }Optional2 spaces (Prettier default)
Java{ ... }Optional4 spaces
C / C++{ ... }OptionalVaries (Google: 2, Linux kernel: tabs)
Go{ ... }OptionalTabs (gofmt enforces this)
Rubydo ... end or { ... }Optional2 spaces
Rust{ ... }Optional4 spaces (rustfmt default)
HaskellIndentation or { ; }Optional but idiomatic2 spaces

Python is unique in making indentation mandatory. Haskell has optional significant whitespace, but most Haskellers use braces to avoid the complexity. Python goes all-in.

Challenges

Challenge
Python 3.13.2
Fix the broken indentation

The function average below has indentation problems and a stray semicolon. Rewrite the body so that:

  • It uses four-space indentation throughout.
  • It has no semicolons.
  • It returns the arithmetic mean of numbers, or 0 if the list is empty.

The hidden tests will call average with several inputs.

Challenge
Python 3.13.2
Rewrite with continuation lines

Rewrite the function long_sum below to use implicit continuation inside parentheses instead of backslash continuation. The function should return the sum of all its arguments.

Do not change the function's behavior, just improve its style.

Test your knowledge

QuestionSelect one

What delimiter does Python use to mark code blocks?

Curly braces { ... }

Keywords begin ... end

Indentation

Parentheses ( ... )

QuestionSelect one

What does PEP 8 recommend for indentation?

A single tab character

Two spaces

Four spaces

Eight spaces

QuestionSelect one

What error does Python 3 raise if you mix tabs and spaces in the same block?

SyntaxError

IndentationError

TabError

RuntimeError

QuestionSelect one

Which tool is the most popular Python code formatter?

pylint

flake8

black

mypy

Now that the rules of the road are clear, we will start using them to build real programs, starting with variables and data types.

On this page