Python Syntax — The Complete Rulebook
A deep, structured walkthrough of every rule that shapes valid Python code — indentation, identifiers, keywords, comments, statements, operators, and the errors that catch beginners off guard.
Last Updated
March 2026
Read Time
28 min
Level
Beginner
What Does 'Syntax' Actually Mean in Python?
In everyday English, syntax refers to the rules that govern how words combine into valid sentences — you can't rearrange them however you like and still be understood. Programming languages work the same way. Python syntax is the complete set of rules that determine which arrangements of characters, keywords, and symbols form a valid, runnable Python program, and which ones the interpreter will reject before your code even gets a chance to execute.
This distinction matters more than it might seem at first. A program can be syntactically perfect and still be logically wrong — for example, calculating a discount incorrectly — but it will still run without complaint, because the interpreter only checks structure, not intent. Conversely, a program with a single misplaced colon or an inconsistent indent will refuse to run at all, regardless of how sound the underlying logic is. Learning syntax, therefore, is really about learning the shape Python expects your ideas to take, so the interpreter can understand what you're asking it to do.
Python's syntax was deliberately designed to be minimal and close to natural language. Where many languages require punctuation-heavy structures — curly braces, semicolons, explicit type declarations — Python strips almost all of that away, relying instead on consistent indentation and a small set of clear keywords. The tradeoff is that Python is stricter about the few rules it does have, particularly around whitespace, precisely because those rules are doing the structural work that braces do elsewhere.
Why Learn Syntax Before Anything Else
It's tempting to skip straight to 'interesting' topics like functions, loops, or classes, treating syntax as boring scaffolding to get through quickly. In practice, the opposite approach pays off. Every single concept you learn afterward — variables, conditionals, loops, functions, classes — is expressed through syntax. If the underlying rules aren't second nature, every new topic becomes twice as hard, because you're simultaneously learning a new concept and re-deriving basic structural rules you should already know cold.
There's also a diagnostic benefit. The vast majority of errors a beginner encounters in their first few weeks are not logic errors — they're syntax errors: a missing colon, inconsistent indentation, an unclosed string, a misspelled keyword. Recognising these instantly, rather than treating every red error message as a mystery, is what separates someone who is fighting their tools from someone who is actually learning to program. This page is built to get you to that point as directly as possible.
The Basic Structure of a Python Program
Every Python program, no matter how large, is built from the same handful of ingredients: statements, expressions, and blocks. Understanding how these three fit together gives you a mental map for reading any Python file, even one you've never seen before.
A statement is a complete instruction that Python executes — assigning a value to a variable, printing something, importing a module, or defining a function. A expression is anything that evaluates to a value, such as 3 + 4, len(name), or age >= 18. Expressions are usually found inside statements — for example, in total = price * quantity, the right-hand side price * quantity is an expression, and the whole line is a statement. A block is a group of statements that belong together logically, such as everything that should run inside an if condition or a for loop — and in Python, blocks are defined purely through indentation, not through any bracket or keyword.
# A statement: performs an action
price = 500 # assignment statement
quantity = 3 # assignment statement
# An expression inside a statement
total = price * quantity # 'price * quantity' is the expression
# A block: grouped statements under a condition
if total > 1000:
print("Bulk order") # inside the block
print("Apply discount") # inside the block
print("Order processed") # outside the block, always runsNotice that the final print statement isn't indented, so Python treats it as sitting outside the if block — it will run regardless of whether the condition was true. This single example already demonstrates the core mechanism behind almost all of Python's structural syntax: indentation isn't cosmetic, it's how the interpreter knows what belongs to what.
Indentation — Python's Most Distinctive Rule
If there is one rule that defines Python's identity more than any other, it's this: indentation is not a style choice, it is the syntax. Languages like Java, C++, and JavaScript use curly braces { } to mark the start and end of a block, and indentation within those braces is purely a formatting convention left to the programmer's discretion — you could write badly-indented Java and it would still run perfectly. Python removed the braces entirely and made the whitespace itself carry that structural meaning, which is why getting indentation wrong doesn't just look messy in Python — it actively breaks the program.
age = 20
if age >= 18:
print("You are an adult")
if age >= 65:
print("You are a senior citizen")
else:
print("You are not a senior citizen")
else:
print("You are a minor")Each new level of nesting — an if inside another if, for instance — adds one more indentation level, typically another four spaces. The Python interpreter tracks these levels internally, and if a line's indentation doesn't cleanly match one of the levels currently open, it raises an IndentationError before your program runs at all.
- ▶
Standard convention — PEP 8, Python's official style guide, recommends exactly 4 spaces per indentation level. This is what virtually every professional codebase and every code editor's default Python configuration uses.
- ▶
Never mix tabs and spaces — Python 3 explicitly forbids mixing tabs and spaces within the same block, and will raise a TabError if it detects this, because the two can look identical on screen but be interpreted completely differently.
- ▶
Consistency within a block — every statement at the same logical level must use exactly the same indentation. Four spaces on one line and five on the next, even if both look 'about right' visually, will cause an error.
- ▶
Blank lines are safe — an empty line inside a block doesn't need to be indented and doesn't break the structure; Python simply ignores blank lines when tracking indentation.
if True:
print("This line is indented correctly")
print("This line has inconsistent indentation")
# Raises: IndentationError: unindent does not match any outer indentation levelIdentifiers — The Rules for Naming Things
An identifier is the name you give to a variable, function, class, module, or any other object you define. Python enforces a small, strict set of rules about what counts as a valid identifier, and understanding these rules upfront saves you from a whole category of confusing early errors.
- ▶
First character — must be a letter (a–z, A–Z) or an underscore (_). It can never be a digit. total1 is valid; 1total is not.
- ▶
Remaining characters — can be any combination of letters, digits, and underscores. Special characters like -, @, #, or spaces are never allowed inside an identifier.
- ▶
Case sensitivity — Python treats uppercase and lowercase letters as completely distinct. Age, age, and AGE are three separate, unrelated identifiers.
- ▶
Reserved keywords are off-limits — you cannot name a variable if, for, class, or any other reserved keyword, since Python needs those words exclusively for its own grammar.
- ▶
No length limit in practice — Python doesn't enforce a maximum identifier length, though extremely long names hurt readability far more than they help.
Beyond the hard rules the interpreter enforces, the Python community follows a set of widely-adopted naming conventions from PEP 8 that, while not mandatory, are expected in almost any professional or open-source codebase:
Reserved Keywords — Words You Can't Reuse
Python reserves a fixed set of words that carry special grammatical meaning and cannot be used as identifiers under any circumstances. As of Python 3.12, there are 35 reserved keywords. You don't need to memorise this list deliberately — it becomes familiar naturally within your first couple of weeks of writing code — but it's useful to see the full picture at least once.
- ▶
Value keywords — True, False, None
- ▶
Logical operators — and, or, not, is, in
- ▶
Control flow — if, elif, else, for, while, break, continue, pass
- ▶
Function & class definitions — def, return, class, lambda, yield
- ▶
Exception handling — try, except, finally, raise, assert
- ▶
Imports & scope — import, from, as, global, nonlocal, del
- ▶
Context & async — with, async, await
- ▶
Structural — match, case (introduced as soft keywords in Python 3.10 for structural pattern matching)
You can view the complete, always-current list directly from the interpreter itself at any time by typing help("keywords") inside a Python shell, or by importing the keyword module and printing keyword.kwlist. A small subset of these — like match, case, and type — are technically 'soft keywords,' meaning they only carry special meaning in specific contexts and can still be used as ordinary variable names elsewhere, unlike the fully reserved words above.
Comments and Docstrings — Writing Notes Into Your Code
Comments let you leave explanatory notes inside your source code that the interpreter completely ignores when running the program. In Python, a single-line comment starts with a hash symbol # and continues to the end of that line.
# Calculate the total price including tax
price = 500
tax_rate = 0.18 # 18% GST
total = price * (1 + tax_rate)
print(total) # displays the final amountPython has no dedicated multi-line comment symbol the way some languages do. Instead, developers commonly use a triple-quoted string — """ ... """ — spanning multiple lines, which Python evaluates as a string literal that is simply discarded if it isn't assigned or used, achieving a similar visual effect.
When that same triple-quoted string appears as the very first statement inside a module, function, class, or method, it takes on a special role: it becomes a docstring. Unlike an ordinary comment, a docstring is not discarded — it's stored and made accessible at runtime through the object's __doc__ attribute, and it's what documentation tools and the built-in help() function display when someone inspects your code.
def calculate_area(radius):
"""
Calculate the area of a circle given its radius.
Returns the result as a float.
"""
return 3.14159 * radius ** 2
print(calculate_area.__doc__)Good comments explain why code does something, not what it does — the code itself already shows what's happening; the comment should add context a reader couldn't get from the code alone, such as a business reason, a workaround for a known limitation, or a warning about a non-obvious edge case.
Statements vs Expressions — A Distinction Worth Getting Right
Beginners often use the words 'statement' and 'expression' interchangeably, but the distinction actually explains several syntax rules that otherwise seem arbitrary. An expression always produces a value — 5 + 3, name.upper(), and age > 18 are all expressions, because each one resolves to something: a number, a string, or a boolean. A statement, on the other hand, performs an action and does not itself produce a usable value — if, for, import, and assignment are all statements.
This distinction is why, for instance, you cannot write print(x = 5) in older Python versions to both assign and print in one call — assignment is a statement, not an expression, so it doesn't produce a value that print() could receive as an argument. Python 3.8 introduced the walrus operator := specifically to bridge this gap in limited situations, allowing an assignment to occur as part of a larger expression.
# Traditional approach: two separate statements
count = len("hello")
if count > 3:
print(f"Length is {count}")
# Using the walrus operator: assignment inside an expression
if (count := len("hello")) > 3:
print(f"Length is {count}")Every expression can appear inside a larger expression or as part of a statement, but statements generally cannot be nested inside expressions — this asymmetry is a direct consequence of the fact that expressions must resolve to a value, while statements exist purely to cause an effect.
Variable Assignment — The Syntax of Storing Data
Creating a variable in Python requires no type declaration and no special keyword — you simply write a name, an equals sign, and a value. The interpreter figures out the type from the value itself, a behaviour known as dynamic typing.
name = "Riya" # string
age = 21 # integer
height = 5.6 # float
is_student = True # boolean
# Multiple assignment on one line
x, y, z = 1, 2, 3
# Assigning the same value to multiple variables
a = b = c = 0
# Type hints (optional, purely informational)
score: int = 95Python also supports augmented assignment operators that combine an operation with assignment in a single step, mirroring similar syntax in languages like Java or JavaScript: x += 1 is shorthand for x = x + 1, and the same pattern applies to -=, *=, /=, //=, %=, and **=. The type hint syntax shown above, using a colon after the variable name, is entirely optional and purely advisory — Python does not enforce it at runtime, but tools like linters and IDEs use it to catch potential type mismatches before you run the code.
Operators — The Symbols That Build Expressions
Operators are the symbols Python uses to combine values into expressions. While later pages cover each category in depth, understanding their basic syntax now makes every example from this point forward easier to read.
One syntax detail that catches beginners coming from other languages: Python has no ++ or -- increment/decrement operators at all. Where Java or C++ would write count++, Python requires the fuller count += 1. This was a deliberate design decision — the Python core developers considered the terse increment syntax more prone to subtle bugs than it was worth saving in keystrokes.
The Syntax of print() and input()
Almost every Python program you write in your first weeks will involve print() for output and input() for accepting user data, so their syntax is worth examining closely rather than treating as a black box.
print("Hello, World!")
# Multiple values, separated by a space by default
print("Name:", "Riya", "Age:", 21)
# Custom separator and line ending
print("A", "B", "C", sep=" - ", end="!\n")
# f-string formatting — the modern, preferred approach
name = "Riya"
age = 21
print(f"{name} is {age} years old")The print() function accepts any number of positional arguments, joins them with the string given to its sep parameter (a single space by default), and finishes the line with whatever string is given to end (a newline character by default). The f-string syntax — a lowercase or uppercase f immediately before the opening quote — lets you embed variables and even full expressions directly inside a string using curly braces, and has been the preferred formatting approach since Python 3.6.
name = input("Enter your name: ")
age_text = input("Enter your age: ")
age = int(age_text) # input() always returns a string
print(f"Hello {name}, next year you'll be {age + 1}")A syntax detail beginners frequently overlook: input() always returns a string, no matter what the user types. If you need a number, you must explicitly convert it using int() or float() — skipping this step and trying to do arithmetic directly on the result of input() is one of the most common early runtime errors.
The Syntax Shape of Conditionals and Loops
While control flow is covered in full depth on its own dedicated page, it's worth seeing the basic syntax pattern here, because every conditional and loop in Python follows the exact same structural template: a keyword, a condition or iterable, a colon, and an indented block.
# if / elif / else
if condition_one:
pass
elif condition_two:
pass
else:
pass
# for loop
for item in some_iterable:
pass
# while loop
while condition:
passEvery one of these keywords is followed by a colon, and every colon is followed by an indented block on the next line (or, for very short bodies, a single statement can technically follow the colon on the same line — though PEP 8 discourages this for readability). Forgetting the colon is one of the single most common syntax errors beginners make, and the interpreter's error message — SyntaxError: expected ':' — points directly at the missing character.
The Syntax of Defining a Function
Functions follow the same colon-and-indent template as conditionals and loops, introduced by the def keyword.
def greet(name, greeting="Hello"):
"""Return a greeting message for the given name."""
message = f"{greeting}, {name}!"
return message
print(greet("Riya"))
print(greet("Aman", greeting="Welcome"))- ▶
def keyword — signals the start of a function definition, followed by the function name and a parenthesised parameter list
- ▶
Default parameter values — writing greeting="Hello" makes that parameter optional; if the caller doesn't supply it, Python uses the default
- ▶
The colon and indented body — identical structural rule to if, for, and while blocks
- ▶
return statement — optional; a function without one implicitly returns None
Line Continuation, Semicolons, and Multiple Statements
In most languages, a semicolon marks the end of every statement. Python doesn't require this — a newline is normally sufficient to end a statement — but semicolons are still legal, and occasionally used to place multiple short statements on a single line.
# Semicolons are optional but legal
a = 1; b = 2; c = 3
print(a, b, c)
# Explicit line continuation with a backslash
total = 1 + 2 + 3 + \
4 + 5 + 6
# Implicit line continuation inside brackets — the preferred style
total = (1 + 2 + 3 +
4 + 5 + 6)
long_list = [
"apple",
"banana",
"cherry",
]PEP 8 explicitly discourages using semicolons to cram multiple statements onto one line, since it hurts readability without any real benefit — Python's newline-based statement separation already does the job cleanly. For splitting a genuinely long line across multiple physical lines, PEP 8 also recommends the implicit continuation shown above — wrapping the expression inside parentheses, brackets, or braces — over the explicit backslash, because it's visually cleaner and less fragile (a trailing space after a backslash silently breaks the continuation, which is a notoriously hard bug to spot).
Python Syntax vs Other Languages — A Side-by-Side View
Seeing the same simple logic expressed in different languages makes Python's syntax choices concrete rather than abstract.
The single biggest structural difference is the first row: everywhere else, curly braces mark a block, and indentation is a courtesy for human readers. In Python, indentation is the block marker, which is precisely why Python code across different codebases tends to look far more visually consistent than equivalent code in brace-based languages, where formatting style varies wildly between teams.
Common Syntax Errors and How to Read Them
A syntax error means Python could not even parse your code into a valid structure — it never got the chance to run anything. Learning to recognise these quickly, directly from the error message, is one of the fastest ways to speed up as a beginner.
Two habits eliminate the majority of these errors before they happen: configuring your editor to insert spaces (not literal tab characters) whenever you press Tab, and getting into the routine of typing the colon and the next line's indentation together as a single motion, rather than as two separate steps you might forget to complete.
Putting the Syntax Together — A Complete Example
Here's a small, complete program that intentionally uses almost every syntax element covered on this page in one place — comments, variables, an f-string, a conditional, a loop, and a function — so you can see how they combine into a real, working piece of code rather than isolated snippets.
def classify_marks(marks):
"""Return a grade label based on a numeric mark out of 100."""
if marks >= 90:
grade = "A"
elif marks >= 75:
grade = "B"
elif marks >= 50:
grade = "C"
else:
grade = "Fail"
return grade
# List of (name, marks) pairs to process
students = [("Riya", 92), ("Aman", 68), ("Kabir", 40)]
for name, marks in students:
grade = classify_marks(marks)
print(f"{name} scored {marks} — Grade {grade}")Output
Riya scored 92 — Grade A Aman scored 68 — Grade C Kabir scored 40 — Grade FailPractice This Code — Live Editor
Interview Questions on Python Syntax
Practice Questions — Test Your Syntax Knowledge
1. Identify the syntax error in this code and explain the fix: 'if age > 18\n print("adult")'
Easy2. Is 'total-price' a valid Python identifier? Why or why not?
Easy3. What is the output of 'print(type(input("Enter a number: ")))' if the user types 42?
Easy4. Explain why 'x = (y := 10) + 5' is valid Python but 'x = (y = 10) + 5' is not.
Medium5. Why might two blocks of code that look identically indented in a text editor still raise a TabError?
Medium6. Rewrite the following using an f-string instead of comma-separated print arguments: print("Name:", name, "Age:", age)
Medium7. What is the difference in behaviour between using a backslash for line continuation and wrapping an expression in parentheses across multiple lines?
HardConclusion — Syntax Is a Foundation, Not a Finish Line
Everything covered on this page — indentation, identifiers, keywords, comments, statements, operators, and the errors that come from getting any of these wrong — forms the grammar you'll use in literally every Python program you ever write. None of it is meant to be memorised through repetition alone; it becomes automatic simply by writing code regularly and paying attention when the interpreter pushes back with an error.
The genuinely useful skill isn't reciting these rules from memory — it's recognising, within a few seconds of seeing a red error message, which rule was broken and how to fix it. That instinct is what lets you stop thinking about syntax altogether and start focusing entirely on the logic of what you're actually trying to build, which is where Python becomes genuinely enjoyable to work in.
From here, the natural next step is exploring Python's built-in data types in depth — strings, integers, floats, booleans, lists, tuples, dictionaries, and sets — since every syntax rule covered here applies directly to how you'll create, read, and manipulate them.