Beginner14 min

Syntax, indentation, and comments

The rules Python enforces: indentation blocks, statements, line continuation, comments, and docstrings.

Why this matters in AI / ML / GenAI

Indentation errors are the first wall every beginner hits, and they still bite experienced engineers who paste code out of a notebook or a chatbot. Knowing the rules means you can fix the error instead of guessing.

Indentation is the block structure

Most languages mark blocks with braces. Python uses indentation, so whitespace is part of the grammar.

Rules that matter:

  • A colon : ends the line that opens a block (if, for, while, def, class, try, with).
  • Everything in the block is indented by the same amount.
  • Four spaces per level is the universal convention. Never mix tabs and spaces — Python 3 rejects it with TabError.
  • The block ends when indentation returns to the outer level.

Two errors you will see:

  • IndentationError: expected an indented block — you opened with a colon but did not indent.
  • IndentationError: unindent does not match any outer indentation level — the levels are inconsistent, usually mixed tabs and spaces from copy-paste.

Configure your editor to insert spaces when Tab is pressed. That one setting removes an entire class of errors.

Statements and line length

One statement per line, no semicolons needed. Python accepts a = 1; b = 2 but nobody writes that.

Long lines break naturally inside brackets (), [], {} — no continuation character required. This is why function calls with many arguments are written one argument per line.

The backslash \ also continues a line, but it is fragile (a trailing space after it breaks the file). Prefer brackets.

PEP 8 suggests 79 characters; most teams settle on 88 or 100 and let a formatter such as ruff or black enforce it.

Comments and docstrings

# starts a comment to end of line. Python has no block comment syntax.

A docstring is a string literal as the first statement of a module, function, or class. Unlike a comment it is stored on the object and readable at runtime through help() or __doc__. Editors show it on hover, and API documentation is generated from it.

Comment the why, not the what. # add 1 to i is noise. # offset by 1 because the API is 1-indexed is worth keeping.

Naming conventions carry meaning in Python:

StyleUsed for
snake_casevariables, functions, modules
PascalCaseclasses
UPPER_CASEconstants
_leadinginternal, do not touch from outside
__dunder__Python's own special methods

Copy-paste examples

Copy into your own editor, or load one into the compiler below and press Run.

Indentation defines the block

The indented lines belong to the if; the last line always runs.

score = 0.85

if score > 0.7:
    print("high confidence")
    print("still inside the if block")
print("outside the block — always runs")

for i in range(3):
    if i % 2 == 0:
        print(i, "even")
    else:
        print(i, "odd")

Breaking long lines inside brackets

No backslash needed. This is how real config and API calls are written.

config = {
    "model": "gpt-4.1-mini",
    "temperature": 0.2,
    "max_tokens": 512,
}

def train(
    model_name,
    epochs=3,
    learning_rate=2e-5,
    batch_size=16,
):
    return f"{model_name}: {epochs} epochs at lr={learning_rate}"

print(config)
print(train("bert-base", epochs=5))

Docstrings vs comments

The docstring is retrievable at runtime; the comment is not.

def cosine_similarity(a, b):
    """Return the cosine similarity between two equal-length vectors.

    Args:
        a: First vector as a list of floats.
        b: Second vector as a list of floats.

    Returns:
        A float between -1.0 and 1.0.
    """
    # guard against a zero vector, which would divide by zero
    dot = sum(x * y for x, y in zip(a, b))
    norm_a = sum(x * x for x in a) ** 0.5
    norm_b = sum(y * y for y in b) ** 0.5
    if norm_a == 0 or norm_b == 0:
        return 0.0
    return dot / (norm_a * norm_b)

print(round(cosine_similarity([1, 2, 3], [2, 4, 6]), 4))
print(cosine_similarity.__doc__.splitlines()[0])

Naming conventions in one file

Style signals intent to the next reader — follow it exactly.

MAX_TOKENS = 4096          # constant

class PromptBuilder:       # class: PascalCase
    def __init__(self, system_prompt):
        self.system_prompt = system_prompt   # public attribute
        self._call_count = 0                 # internal, leave alone

    def build(self, question):               # method: snake_case
        self._call_count += 1
        return f"{self.system_prompt}\n\nQ: {question}"

builder = PromptBuilder("Be concise.")
print(builder.build("What is Python?"))
print("MAX_TOKENS:", MAX_TOKENS)

Fix the indentation

Try it — in-browser Python

The else block is under-indented. Line it up with the if, then press Run.

Output

Python runs in your browser. First run downloads the runtime.

Press Run (or Ctrl+Enter) to execute.

CPython in WebAssembly. Stdlib works. NumPy, pandas, scikit-learn and Matplotlib load on demand, and charts render below. No input(), no GPU, no network installs.

Takeaways

  • Indentation is syntax: four spaces per level, never mix tabs and spaces.
  • Break long lines inside brackets rather than with a backslash.
  • Docstrings are readable at runtime; comments explain why, not what.