Lesson Review
Python's Logic & Structure
ifforTrue····indent# comment
The rules that decide how Python reads your code.
By the end of this lesson you will be able to:
- Identify Python's reserved keywords and explain why they cannot be used as variable names.
- Tell the difference between a keyword and a built-in name like
print.
- Explain how indentation defines code blocks, and fix indentation errors.
- Write single-line comments and multi-line comments, and explain how triple-quoted strings fit in.
How to use this page: Use Next and Back (or the arrow keys). Click keywords to learn what they do, test your own variable names in the name checker, and use Step to watch which lines Python runs and which it skips.
Words you will hear today
| Word | What it means | Example |
| statement | One complete instruction, usually one line | score = 85 |
| keyword | A word reserved by Python for its own grammar | if, for, True |
| header | A line ending in a colon that starts a block | if score >= 70: |
| block | The indented lines that belong to a header | the lines under an if |
| indentation | Spaces at the start of a line | 4 spaces per level |
| comment | A note for people that Python ignores | # average the scores |
- Keywords, indentation, and comments are the "grammar" of Python.
- Statement, keyword, header, block, indentation, comment.
Every language has grammar rules. In English, we use capital letters and periods. Python's grammar includes special reserved words, indentation, and comments. Today we look at all three, and why breaking these rules gives the errors you have probably already seen.
Structure
How Python reads a program
- A program is a list of statements (instructions), usually one per line.
- Python runs them from top to bottom.
- Python is case sensitive:
print, Print, and PRINT are three different names.
- Some lines start a block by ending in a colon
: (like if, for, while). The indented lines under them are the block.
- Anything after a
# (outside quotes) is a comment, and Python ignores it.
Python figures out what each line means by reading its words in order. Some words, the keywords, are reserved as instructions to Python. That is why they get special rules.
# Grade checker <- comment
score = 85 # statement
if score >= 70: # starts a block
print("You passed!") # inside the block
print("Done") # back outside
You passed!
Done
Tracing the example
- Line 1 is a comment. Python skips it.
- Line 2 stores
85 in score.
- Line 3 checks
85 >= 70. It is True, so Python goes into the block.
- Line 4 is the block. It prints
You passed!
- Line 5 is back at the left edge, so it is not part of the
if. It always runs and prints Done.
What if score = 60? Line 3 is False, so Python skips line 4 and jumps to line 5. The output is only Done.
Blank lines are ignored, so you can use them to separate parts of your program and make it easier to read.
- Statements, top to bottom, case sensitive.
- Colon starts a block; indentation shows what is inside it.
- A False condition skips the whole indented block.
This tiny program shows all three topics for today. The first line is a comment. The word if is a keyword. And the indented print is inside the if's block because of its four spaces. Let's look at each piece.
Reserved Keywords
What are reserved keywords?
Keywords (also called reserved words) are words that have a special meaning in Python. They are part of the language itself, so they cannot be used as ordinary names for variables.
Python 3.13 has 35 keywords, listed in the official Python documentation:
FalseNoneTrueandasassertasync
awaitbreakclasscontinuedefdelelif
elseexceptfinallyforfromglobalif
importinislambdanonlocalnotor
passraisereturntrywhilewithyield
- They must be spelled exactly as shown. Only
True, False, and None start with a capital letter.
- Because Python is case sensitive,
If or TRUE are not keywords. (They are allowed as names, but please do not use them. They are confusing!)
- You can see the list yourself in Python:
import keyword
print(keyword.kwlist)
Soft keywords: Python also has 4 soft keywords (match, case, type, _). They only act as keywords in certain statements, so they are allowed as variable names. They will not come up much in this class.
You do not need to memorize all 35
Most of them come up later or never in this class. These are the ones you will use most, grouped by job:
- Values:
True, False, None
- Logic:
and, or, not, in, is
- Decisions:
if, elif, else
- Loops:
for, while, break, continue, pass
- Functions and modules:
def, return, import, from, as
Let your editor help: editors like IDLE show keywords in a special color (often orange or purple). If a name you typed suddenly changes color, it is probably a keyword, so pick another name.
- 35 keywords in Python 3.13. Spelling and capitals must match exactly.
- keyword.kwlist shows the list.
- Editors color keywords; if your name changes color, rename it.
These 35 words are the vocabulary Python has reserved for itself. You already know about a third of them: if, else, for, while, True, and so on. Notice that only True, False, and None are capitalized. Everything else is lowercase.
Reserved Keywords
Keyword explorer
Keywords grouped by the job they do. Click any keyword to see what it means. A marks keywords we have used in class so far.
One keyword, more than one job
A few keywords are used in more than one way, and Python tells which one you mean from the rest of the line:
for letter in "abc": # in: go through each item
print(letter)
print("a" in "cat") # in: is it inside? True
Similarly, else can follow an if and (as you will see later) other statements too. The surrounding words decide its meaning.
- Group keywords by job: values, logic, decisions, loops, functions, modules, errors.
- You do not need to memorize what all of them do yet. You do need to know not to use them as names.
- Some keywords, like in, have more than one job.
You do not need to know what every keyword does today. Some, like async and await, are for advanced programs. What you do need is to recognize them, so you never try to use one as a variable name. Click a few you have not seen yet.
Reserved Keywords
Why can't a keyword be a variable name?
When Python reads a line, it looks at the words to decide what kind of instruction the line is. A line that starts with for must be a loop. A line that starts with if must be a decision.
If you write for = 10, Python sees the keyword for and expects a loop like for x in ...:. The = does not fit that pattern, so Python stops with a SyntaxError before your program even starts.
Think of it like a game's rule words. In a board game, "Start" and "Go to jail" are reserved squares. You cannot rename your player "Go to jail" without confusing everyone. Keywords are Python's reserved squares.
| Line | Python 3.13 says |
class = "Period 3" | SyntaxError: invalid syntax |
True = 5 | SyntaxError: cannot assign to True |
None = 0 | SyntaxError: cannot assign to None |
try = 3 | SyntaxError: expected ':' |
Pick a name and run it. Notice that the error stops the program before any line prints, because Python checks the whole file first.
Why is it a SyntaxError and not a runtime error?
Python checks the grammar of the whole file before running any of it. A keyword in the wrong place breaks the grammar, the same way "The dog the." breaks an English sentence. That is why, in the demo, even line 1 does not print: Python never started running.
Compare: a misspelled variable like prnt("hi") is grammatically fine, so Python starts running and stops only when it reaches that line, with a NameError. A keyword used as a name stops everything before the first line runs.
- Keywords tell Python what kind of statement a line is.
- Using one as a name breaks the grammar, so it is a SyntaxError.
- Keyword misuse is caught before anything runs.
Here is the key idea. Python decides what a line means based on its keywords. If keywords could also be variable names, Python could not tell whether "for" starts a loop or is a variable. So the rule is simple: keywords are reserved, period. Try the different names in the editor, and notice that line 1 never prints, because a SyntaxError stops everything.
Naming Rules
Name checker
Rules for variable names
- Use only letters, digits, and underscores (
_).
- Do not start with a digit.
score2 is fine, 2score is not.
- No spaces and no dashes. Use underscores:
high_score.
- Not a keyword.
Style (PEP 8, Python's style guide)
- Variable names should be lowercase, with words separated by underscores:
total_points.
- If you really want a keyword-like name, add a trailing underscore:
class_.
- Avoid single-letter names
l, O, and I. They look like 1 and 0 in some fonts.
Type any name to check it. Try class, Class, class_, print, 2nd_place, high-score, and my_score.
Why these rules exist
- No leading digit: Python needs to tell names from numbers instantly.
2e5 is actually a float (200000.0), so if names could start with digits, Python could not tell which you meant.
- No dashes:
high-score already means "high minus score."
- No spaces:
high score would look like two separate names.
Remember case: score, Score, and SCORE are three different variables. A common bug is creating Score = 0 and later typing score += 1, which gives a NameError.
- Letters, digits, underscores; no leading digit; not a keyword.
- Style: lowercase_with_underscores.
- Names cannot start with a digit because 2e5 is a number.
- score and Score are different variables.
The name checker uses the real rules, and the error messages come straight from Python 3.13. Try class, then Class with a capital C, then class with an underscore. Two of those are allowed, but only one is a good choice.
Naming Rules
Watch out: print is not a keyword
Words like print, input, len, list, str, and sum are built-in names, not keywords. Python lets you use them as variable names...
...but then the variable replaces the built-in tool for the rest of your program. That is usually a bug waiting to happen.
Example: after print = 5, the name print means the number 5, not the print function. Calling print("ok") gives TypeError: 'int' object is not callable.
Tip: if a name shows up in a special color in your editor and you did not create it, it is probably a built-in. Pick a different name, like total instead of sum.
Easy names to accidentally take over
| Tempting name | Built-in it hides | Use instead |
sum | adds up a list | total |
max / min | biggest / smallest value | highest, lowest |
list | makes a list | names, scores |
str | converts to text | text, message |
input | reads what the user types | answer, user_input |
Why it causes trouble later: the error does not happen on the line where you made the variable. It happens much later, when you try to use the built-in tool. That makes the bug hard to connect to its cause. Rename the variable and run the program again.
- Keywords cannot be names: SyntaxError.
- Built-in names can be names, but you lose the built-in tool.
- Use total, highest, names instead of sum, max, list.
This one is sneaky. print is not on the keyword list, so Python allows print equals 5 without complaining. The problem shows up later, when you try to print something and Python says an integer is not callable. Run it, then uncheck the box and run it again.
Indentation
Indentation defines code blocks
A code block is a group of lines that belong together. Many languages use curly braces { } to mark blocks. Python uses indentation: the spaces at the start of a line.
- A header line ends with a colon
: (if, elif, else, for, while, and others).
- The lines under it that are indented further make up its block.
- Lines in the same block must have the same indentation.
- The block ends when a line goes back to the earlier indentation.
The standard is 4 spaces per level. That is what PEP 8 recommends, and IDLE inserts 4 spaces when you press Tab in its editor.
Click a header line (one that ends with :) to highlight its block.
Why did Python choose indentation?
In languages that use braces, good programmers indent anyway so the code is readable. Python made that indentation required, so the way the code looks is always the way it runs. You can never have code that looks like it is inside an if but really is not.
// Java uses braces to mark the block
if (score >= 70) {
System.out.println("Pass");
}
# Python uses the colon and indentation
if score >= 70:
print("Pass")
A block cannot be empty. If you need a header but have nothing to put in it yet, write pass, a keyword that means "do nothing."
- Header ends with a colon; its block is the indented lines below it.
- 4 spaces per level.
- Python makes indentation required, so code looks the way it runs.
- pass fills an empty block.
In Python, spaces are not just for looks. They are how Python knows which lines belong to which statement. Click the if line in the visualizer and see its whole block light up, including the nested if inside it. Then click the nested if and see its smaller block.
Indentation
Try it: four spaces change everything
Line 4 is the same code each time. Only its indentation changes. Pick an indentation and a temperature, then run it.
| Indentation of line 4 | What happens |
| 4 spaces | It is inside the if block. It runs only when the condition is True. |
| 0 spaces | It is outside the block. It always runs. |
| 2 spaces | It matches no level. IndentationError: unindent does not match any outer indentation level |
| 8 spaces | Extra indentation with no new header. IndentationError: unexpected indent |
Trace both versions
| Line 4 indentation | temp = 90 | temp = 70 |
| 4 spaces (inside) | sunscreen, water, nice day | nice day |
| 0 spaces (outside) | sunscreen, water, nice day | water, nice day |
With a hot day, both versions print the same thing. The difference only shows on a cool day. This is why you should test more than one value: a bug in indentation can hide when the condition happens to be True.
Logic error: when the indentation is valid but wrong for what you meant, Python gives no error. It just runs a different program from the one you had in mind.
- Same code, different indentation, different program.
- Indentation must match a level that already exists.
- Test both a True and a False case to catch indentation bugs.
Try temperature 50 with 4 spaces: nothing in the block prints. Switch to 0 spaces: Drink water prints, because now it is outside the if. Then try 2 and 8 spaces and read the two different error messages. Four spaces can completely change what a program does.
Indentation
Blocks inside blocks
A block can contain another header and its own block. Each level adds 4 more spaces.
| Level | Spaces | Example |
| Main program | 0 | for i in range(1, 4): |
| Inside the loop | 4 | if i == 2: |
| Inside the if | 8 | print("two!") |
Tracing tip: to find which block a line is in, slide your finger straight up until you hit a header line with less indentation. That header owns the line.
The output, explained
i is 1
two!
i is 2
i is 3
done
print("two!") is 8 spaces in, inside the if. It runs only when i is 2.
print("i is", i) is 4 spaces in. It is inside the loop but after the if block ends, so it runs every time the loop runs.
print("done") is at 0 spaces, outside the loop. It runs once, at the very end.
- Each nesting level: 4 more spaces.
- A line belongs to the nearest header above it with less indentation.
- 8 spaces: inside the if. 4: inside the loop. 0: after the loop.
Step through this one and watch the levels. The print at 8 spaces only runs when i is 2. The print at 4 spaces runs every time through the loop. And the print at 0 spaces runs once, after the loop ends.
Indentation
Indentation errors and how to fix them
| Problem | Example | Python 3.13 says | Fix |
| Header with no indented block | if True:
print("a") | IndentationError: expected an indented block after 'if' statement on line 1 | Indent the block (or use pass) |
| Extra spaces with no header | x = 1
print(x) | IndentationError: unexpected indent | Remove the extra spaces |
| Going back to a level that never existed | print("a")
print("b") | IndentationError: unindent does not match any outer indentation level | Line it up with an earlier level |
| Mixing tabs and spaces | one line indented with spaces, the next with a tab | TabError: inconsistent use of tabs and spaces in indentation | Use spaces only (4 per level) |
Consistency is what matters to Python. A block indented 8 spaces still works, as long as every line in it uses 8. But stick with 4: it is the standard, and everyone reading your code expects it.
Tabs vs. spaces: a tab and 4 spaces can look the same on screen but are different characters. Python's documentation warns against mixing them in one file. PEP 8 says spaces are preferred.
Reading an IndentationError
The message gives a line number. Look at that line and the one just above it. The problem is usually that the two lines do not line up the way you meant, or the line above is a header with nothing indented under it.
Editor tricks that save time
- To move a group of lines in or out together, select them and press Tab / Shift+Tab (in IDLE: Ctrl+] to indent and Ctrl+[ to dedent).
- Many editors can show spaces as faint dots. Turn this on if you suspect tabs and spaces are mixed.
- Copying code from a website can bring in tabs or odd spaces. If an error appears on a pasted line, delete the indentation and type 4 spaces yourself.
- Four indentation errors to recognize.
- Use 4 spaces, never mix tabs and spaces.
- Check the error line and the line just above it.
These are the four indentation messages you will see. The first means you forgot to indent. The second means you indented when you should not have. The third means your indentation does not line up with anything. And the fourth means you mixed tabs and spaces, which can look perfect on screen but confuses Python.
Comments
Single-line comments with #
A comment is a note for people. Python ignores it. A comment starts with # and ends at the end of that line.
| Kind | Example |
| Full-line comment | # Calculate the average score |
| Inline comment (after code) | total = 0 # running total |
| Commenting out code (turning it off) | # print("debug") |
- PEP 8 style: start with
# and one space. Put at least two spaces before an inline comment, and use inline comments sparingly.
- A
# inside quotes is just text: print("#1 fan") prints #1 fan.
Step through this program. Comment lines fade out because Python skips them. Watch what happens on line 3.
Commenting out code to find a bug
Putting # in front of a line turns it off without deleting it. This is a common way to find a problem: turn off a suspicious line, run again, and see whether the problem goes away. When you are done, remove the # to turn it back on.
Most editors can do this for many lines at once. In IDLE, select the lines and use Format → Comment Out Region (and Uncomment Region to undo).
Why line 3 of the demo is different: the # in print("#1 fan of Python") is inside quotes. Quotes always win: everything between them is part of the string, including #.
- # starts a comment, which ends at the end of the line.
- A # inside a string is not a comment.
- Comment out a line to test whether it causes a bug.
Comments are notes to yourself and to anyone else who reads your code. Step through the editor: the comment lines never turn green, because Python skips them completely. But look at line 3. It is a triple-quoted string, and it does turn green. That is our next topic.
Comments
Multi-line comments
Python's only comment symbol is #. There is no special symbol for a multi-line comment. Programmers use two approaches:
1. Several # lines (a "block comment")
# This program calculates a final grade.
# It averages the test scores, then adds
# extra credit if the student earned any.
This is the approach PEP 8 describes: each line of a block comment starts with # and a single space. Most editors can add # to many lines at once.
2. A triple-quoted string
"""
This program calculates a final grade.
It averages the test scores.
"""
A string in triple quotes (""" or ''') can span many lines. If it is not stored in a variable, it has no effect, so people often use it like a comment.
But it is really a string, not a comment. Python actually creates the string and then throws it away. You saw it run (turn green) on the previous slide. Try it at the prompt below: a # line shows nothing, but a triple-quoted string shows its value.
# just a comment
"""a note"""
Docstrings: when a triple-quoted string is the first thing in a file (or in a function or class), it becomes a docstring. Python saves it as documentation that tools like help() can show. That is the main official use of triple-quoted strings at the top of code.
A docstring you can see
Save this as a file and run it. __doc__ (two underscores on each side) is a special name that holds the file's docstring:
"""Grade calculator: averages three test scores."""
print(__doc__)
Grade calculator: averages three test scores.
That is the difference: a # comment is thrown away completely, but a docstring is kept so tools (and your program) can read it.
Which should you use? Use # lines for notes inside your code. Use one triple-quoted docstring at the very top of a file to describe what the whole program does.
- # is the only comment symbol.
- Multi-line: several # lines (PEP 8), or a triple-quoted string (really a string; a docstring when first).
- Comments are discarded; docstrings are kept and can be read.
Here is a surprise for many people: Python does not have a true multi-line comment. The official way is several lines that each start with a pound sign. Triple-quoted strings work like comments, but they are really strings. Type one into the prompt and Python shows its value. A real comment shows nothing.
Comments
Writing good comments
Not helpful: repeats the code
x = x + 1 # add 1 to x
Helpful: explains why
x = x + 1 # count this student as present
Out of date: worse than nothing
# Passing score is 60
if score >= 70:
print("Pass")
- Explain why the code does something, not what every symbol means.
- Put a comment at the top of your program saying what it does.
- Use comments to label sections of longer programs.
- Update comments when you change the code.
- Use good variable names, so the code explains itself.
PEP 8 says it directly: comments that contradict the code are worse than no comments. Always keep your comments up to date when the code changes.
A header comment for your assignments
# Program: grade_calculator.py
# Author: Your Name, Period 3
# Purpose: Averages three test scores and prints a letter grade.
Three lines at the top tell any reader what the file is and who wrote it, before they read a single line of code.
Good names can replace comments
t = s * 0.07 # sales tax
sales_tax = subtotal * TAX_RATE # no comment needed
The second line explains itself. Save your comments for things the code cannot say, like why a choice was made.
- Comment the why, not the obvious what.
- Keep comments up to date.
- Start every program with a short header comment.
A good comment answers the question a reader would ask: why is this here? A comment that just repeats the code wastes space. And a comment that is out of date is actually harmful, because the reader will trust it. Look at the last example: the comment says 60, but the code says 70.
Debugging
Common mistakes
| Mistake | Wrong code | What Python 3.13 says | Fix |
| Keyword as a variable | class = "Period 3" | SyntaxError: invalid syntax | class_name = "Period 3" |
| Assigning to True, False, or None | True = 1 | SyntaxError: cannot assign to True | Use a different name |
| Built-in used as a variable | print = 5 then print("hi") | TypeError: 'int' object is not callable | Rename the variable |
| Name starts with a digit | 2nd_place = "Ben" | SyntaxError: invalid decimal literal | second_place |
| Dash in a name | high-score = 10 | SyntaxError: cannot assign to expression here. Maybe you meant '==' instead of '='? | high_score |
| Forgot to indent the block | if x > 5:
print(x) | IndentationError: expected an indented block after 'if' statement on line 1 | Indent 4 spaces |
| Extra indentation | print(x) with no header above | IndentationError: unexpected indent | Remove the spaces |
| Mixed tabs and spaces | tab on one line, spaces on the next | TabError: inconsistent use of tabs and spaces in indentation | Spaces only |
| Triple quotes never closed | """my notes with no closing """ | SyntaxError: unterminated triple-quoted string literal (detected at line N) | Close it with """ |
| Wrong indentation level | a line at 0 spaces that belongs inside the if | No error. The line runs every time (logic error) | Indent it into the block |
Error messages are from Python 3.13. Older versions word some messages a little differently.
Sort the error by its first word
- SyntaxError: a line is written in a way Python's grammar does not allow (keyword as a name, bad character in a name, unclosed quotes). Nothing ran.
- IndentationError / TabError: the spaces at the start of a line are wrong. Nothing ran.
- TypeError (like
'int' object is not callable): the program ran until it tried to use a value the wrong way. Often caused by a built-in name being reused.
- No error but wrong output: usually a line at the wrong indentation level. Step through it and watch which lines run.
- Name errors: keywords, built-ins, digits, dashes.
- Indentation errors: missing, extra, mismatched, mixed.
- SyntaxError and IndentationError: nothing ran. TypeError: it ran until that line.
Most of these show up as SyntaxError or IndentationError before your program runs anything. The sneakiest one is the last row: a line at the wrong level gives no error at all, it just runs when it should not. That is why tracing your blocks matters.
Practice
Check yourself
Choose an answer, then click Check. This is practice only. Nothing is graded or recorded.
For each question, ask:
- Is this word a keyword (SyntaxError as a name), a built-in (allowed but risky), or just a normal name?
- Which header owns this line? Slide your finger straight up.
- Is the
# inside quotes (text) or outside (a comment)?
- Keywords: reserved. Built-ins: allowed but risky.
- Indentation decides the block.
Take your time with these. For the indentation questions, trace which block each line belongs to before you choose.
Summary
Cheat sheet
Keywords
- 35 reserved words in Python 3.13
- They tell Python what kind of statement a line is, so they cannot be names (SyntaxError)
- Built-ins like
print are not keywords, but do not use them as names either
- Names: letters, digits,
_; no leading digit; lowercase_with_underscores
Indentation
- A header ends with
:
- Its block is the lines indented under it
- 4 spaces per level; same block, same indentation
- Never mix tabs and spaces
Comments
# single-line comment
x = 5 # inline comment
# multi-line comment:
# start every line
# with a hash
"""A triple-quoted string
(really a string)"""
Before you run, check:
- No variable is named after a keyword or a built-in
- Every header line ends with a colon, and its block is indented 4 spaces
- Lines at the end of a block go back to the right level
- Your comments explain why, and they match the code
Key words to know
statement · keyword (reserved word) · built-in · header · block · indentation · IndentationError / TabError · comment · docstring · logic error · PEP 8
- Keywords are reserved. Indentation is structure. # is for comments.
- Know the key words: keyword, built-in, block, docstring, logic error.
Let's wrap up. Keywords are Python's reserved vocabulary, so they cannot be variable names. Indentation is how Python groups lines into blocks, so spaces really matter. And the pound sign starts a comment, while triple-quoted strings are strings that people sometimes use like comments.