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.

1. Read

Understand the idea in plain English first.

2. Run

Load any example into the compiler and press Run.

3. Change

Edit one value, rerun, and learn from the output.

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

Hands-on practice

Compiler on the left. Examples on the right.

On desktop, keep the compiler beside the examples. On mobile, the same blocks stack cleanly. Pick an example, try it in the compiler, then change one small thing.

Fix the indentation

Live Python compiler

Try it — in-browser Python

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

Code editor

Output

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

Press Run (or Ctrl+Enter) to execute.

Runs CPython in your browser. NumPy, pandas, scikit-learn and Matplotlib load on demand. Charts appear below the output. No input(), no GPU, no network installs.

Clear code examples

Every example is copy-ready. Use Try in compiler when you want to experiment without scrolling around.

Example

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")

Example

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))

Example

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])

Example

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)

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.