This lesson introduces the assignment statement and the state diagram, gives the rules for legal variable names, separates expressions from statements, and explains why the same three lines print something at the prompt and nothing in a script.
Subject: Python · 65 slides · code lesson
Open the interactive version of this deck
Title
Python · Chapter 2 — Variables, expressions and statements
§2.1-2.4, pp. 9-11
Objectives
Five things, each one you can check yourself at an interpreter prompt.
Think Python, 2nd edition — Allen B. Downey §2.1-2.4, pp. 9-11 — the pages these objectives are drawn from
Warm-up
Last lesson you computed with Python. This lesson is about the one thing that was missing.
Discussion prompt
You worked out 26.2 times 1.61 at the prompt and got 42.182. Now you want to use that result in three more calculations. With only what you know so far, what would you have to do each time — and what is annoying about it?
Hint: There is nowhere to put the answer.
Answer:
You would have to retype 42.182, or retype the whole multiplication, every single time. Nothing is remembered between lines.
Worse, if the 26.2 turned out to be wrong, you would have to find and fix every place you had typed the result by hand.
The ability to manipulate variables is one of the most powerful features of a programming language, and this is the problem it solves. A variable is a name that refers to a value — so you name the result once and use the name afterwards.
Concept
A variable is a name that refers to a value. Read that as carefully as you read the definition of a program: the variable is the NAME, and it REFERS to something. The name and the value are two different things with a relationship between them.
variable — A name that refers to a value.
A common way to represent variables on paper is to write the name with an arrow pointing to its value. This kind of figure is called a state diagram, because it shows what state each of the variables is in.
Figure (svg): A state diagram with three rows, showing the names message, n and pi each with an arrow pointing to the value they refer to
Think Python, 2nd edition — Allen B. Downey §2.1-2.4, pp. 9-9 — the definition and figure 2.1
Section
Section 1
Concept
An assignment statement creates a new variable and gives it a value. It is written with a single equals sign, and it is not a claim that two things are equal — it is an instruction to make a name refer to a value.
>>> message = 'And now for something completely different'
>>> n = 17
>>> pi = 3.1415926535897932| Name created | Type of value | State after |
|---|---|---|
| message | a str | the name message now refers to that text |
| n | an int | the name n now refers to 17 |
| pi | a float | the name pi now refers to that approximation |
This example makes three assignments. The first assigns a string to a new variable named message; the second gives the integer 17 to n; the third assigns an approximate value of pi to a variable called pi. Notice that assignment produces no output at all — the prompt simply returns.
Think Python, 2nd edition — Allen B. Downey §2.1-2.4, pp. 9-9
Picture it
The equals sign is the instruction to draw the arrow. It always points from the name to the value.
Figure (svg): A state diagram with two rows showing the name n pointing at seventeen and the name pi pointing at a long decimal
Get into the habit of drawing it. In chapter 3 it will explain scope, and in chapter 10 it is the only thing that makes aliasing comprehensible.
Worked example
Three lines. Track the state after each, and predict what is displayed.
>>> miles = 26.2
>>> miles * 1.61
42.182| Line | What kind of line it is | What happens |
|---|---|---|
| miles = 26.2 | an assignment | miles refers to 26.2; nothing displayed |
| miles * 1.61 | an expression using the name | evaluated to 42.182 |
| display | the interpreter shows the value | 42.182 |
Run the assignment and notice what does NOT happen.
Why: The first line assigns a value to miles, but it has no visible effect. No output, no confirmation, just a new prompt.
Use the name in an expression.
Why: Wherever a value could go, a name referring to that value can go. Python looks up what miles refers to and uses it.
Read the result.
Why: It turns out a marathon is about 42 kilometres.
Figure (svg): The state of the program after each line of Worked example using a name after you have made it, drawn as a ladder with one rung per traced line
Only the second line displays anything. The assignment created the name silently, and the expression that used the name produced 42.182.
Verify: Ask what would happen if the second line ran before the first.
Why: Python would report a NameError, because there would be nothing for miles to refer to. That the order matters here is the strongest possible evidence that the assignment really did change the state of the program, even though it printed nothing.
Prediction
This catches almost everybody once. Commit before you read on.
Predict first
You type x = 5 at the prompt and press Enter. What does the interpreter display?
Correct: Nothing at all — just a new prompt. The assignment has an effect but no value to display.
Why: This is the first appearance of the distinction the whole lesson is built on. An assignment is a STATEMENT: it does something, and in general statements do not have values. Since there is no value, there is nothing for the interpreter to display. The silence is not a sign that nothing happened — typing x afterwards proves the name now exists.
Worked example
This line is nonsense as mathematics and completely ordinary as Python. Work out why.
>>> n = 17
>>> n = n + 1
>>> n
18| Line | What happens, in order | State after |
|---|---|---|
| n = 17 | n is created | n refers to 17 |
| n = n + 1 | the right side is evaluated FIRST, using the old n | 17 + 1 gives 18 |
| n = 18 | then the name is pointed at the new value | n refers to 18 |
Read the right-hand side first.
Why: Python evaluates everything to the right of the equals sign before it touches the name on the left. At that moment n still refers to 17, so the right side is 18.
Then perform the assignment.
Why: The name n is pointed at the new value. The old value is simply no longer referred to by n.
Notice why this is not a contradiction.
Why: As mathematics, n equals n plus one has no solutions. As Python it is not a claim at all; it is an instruction with a before and an after.
Figure (svg): A three-rung ladder showing n equals n plus one being evaluated as seventeen plus one and then eighteen being assigned to n
n ends up referring to 18. The right-hand side was evaluated using the old value, and only then was the name pointed at the result.
Verify: Run the same line again and check the value goes to 19.
Why: It does, which confirms the read-then-write order. If assignment were a statement of equality rather than an instruction, running it twice would be meaningless rather than incrementing.
Trap
A student reads n = n + 1 as a mathematical statement, decides it is false or impossible, and concludes they have misunderstood something.
Import the meaning of = from mathematics
Why: In mathematics the equals sign asserts that two things are the same, and that assertion has no before and after.
From there, every line that reassigns a variable looks wrong, and the whole idea of a program changing state over time becomes hard to see.
In Python the single equals sign is an INSTRUCTION, and it has a direction.
Read left-to-right as becomes or is given
Why: n becomes n plus one is not a paradox. It is a perfectly ordinary thing to ask somebody to do.
Evaluate the right, then move the arrow
Why: The right-hand side is computed first, using the values names refer to at that moment.
Python does have a symbol that means is equal to — a double equals sign — and it arrives in chapter 5. Keeping the two apart from the start saves a great deal of confusion later.
Invariant
Step through and watch which arrows move and which stay put.
Step through it
After the third line, what does b refer to — and why did it not change when a did?
The second line copied the ARROW, not a link to a. Once b had its own arrow, later changes to a had nothing to do with it. Chapter 10 revisits this when the values are lists, where the answer is more interesting.
Fill the middle
The state before and after are given. Supply the line that caused the change.
Fill in the blanks
# before: total refers to 20
total = total + 5
# after: total refers to 25
Why: The right-hand side is evaluated using the value total refers to at that moment, which is 20, so total + 5 produces 25 and the name is then pointed at it. Writing simply 25 would also produce the right state, but it would lose the relationship to the old value — and in a real program the old value is usually the point.
Socratic
The silence is a design decision, not an oversight.
Discussion prompt
Suppose every assignment displayed its value, so that x = 5 showed 5. Describe what a twenty-line script would look like when you ran it, and say whether you would want that.
Hint: Count how many assignments a real program performs.
Answer:
A twenty-line script might perform fifteen assignments, so running it would produce fifteen lines of output you did not ask for, mixed in with the output you did.
You would then need a way to suppress them, and the useful default would have been inverted: the common case would need extra syntax and the rare case would be free.
So the rule is: display the values of expressions, because an expression's whole purpose is its value; say nothing about statements, because their purpose is their effect. Print exists for the times you want to see something deliberately.
Section
Section 2
Concept
Programmers generally choose names that are meaningful — they document what the variable is used for. Beyond that, there are exactly three rules about what a name may be, and breaking any of them is a syntax error.
>>> 76trombones = 'big parade'
SyntaxError: invalid syntax
>>> more@ = 1000000
SyntaxError: invalid syntax
>>> class = 'Advanced Theoretical Zymurgy'
SyntaxError: invalid syntax| Attempted name | What is wrong with it | Which rule |
|---|---|---|
| 76trombones | begins with a number | rule 1 |
| more@ | contains an illegal character | rule 2 |
| class | is one of Python's keywords | rule 3 |
Names can be as long as you like. Uppercase letters are legal but conventionally reserved for other purposes, so variables are written in lower case, and the underscore is used to join words: your_name, airspeed_of_unladen_swallow.
Think Python, 2nd edition — Allen B. Downey §2.1-2.4, pp. 9-10
Picture it
All three produce the same message, so knowing the three rules is how you tell them apart.
Figure (svg): Two columns listing illegal variable names beside legal ones, with the rule each illegal one breaks
Notice that every fix is small. The rules are narrow, and almost any name you actually want is available once the punctuation is right.
Worked example
Python gives the same message for all three. Work out which rule each one breaks.
76trombones = 'big parade'
more@ = 1000000
class = 'Advanced Theoretical Zymurgy'| Name | The rule it breaks | A fix |
|---|---|---|
| 76trombones | a name may not start with a digit | rename to trombones76 |
| more@ | the at-sign is not allowed in a name | rename to more_money |
| class | class is a keyword | rename to class_name |
Check the first character.
Why: 76trombones is illegal because it begins with a number. Every other character in it would have been fine.
Check every other character.
Why: more@ is illegal because it contains an illegal character, the at-sign. Letters, digits and underscores are the entire permitted set.
Check the whole name against the keyword list.
Why: class is one of Python's keywords. The interpreter uses keywords to recognise the structure of the program, so they cannot also be names you invent.
Figure (svg): The state of the program after each line of Worked example diagnosing three rejected names, drawn as a ladder with one rung per traced line
One name breaks each rule: a leading digit, an illegal character, and a keyword. All three produce the identical message, invalid syntax, which is why knowing the three rules is worth more than reading the error.
Verify: Apply the fixes and check that all three now assign silently.
Why: trombones76, more_money and class_name are all accepted, and each produces no output — which is what a successful assignment looks like. Getting silence back is the confirmation.
Sorting
Three rules decide all of these. Name the rule as you sort.
Sort into buckets
Sort each proposed name.
Worked example
The first two names are obviously odd-looking. This one looks completely ordinary.
False class finally is return
None continue for lambda try
True def from nonlocal while
and del global not with
as elif if or yield
assert else import pass
break except in raise| Question | Answer | Consequence |
|---|---|---|
| how many | 33 keywords in Python 3 | a fixed, short list |
| why reserved | the interpreter uses them to recognise structure | they cannot be names too |
| memorising | not needed — editors colour them differently | you will see it |
Notice what makes a keyword special.
Why: It is not that the word is important or reserved by convention. The interpreter reads these words to work out the STRUCTURE of your program — where a definition starts, where a loop begins.
See why that rules out using one as a name.
Why: If class could also be a variable, the interpreter would have no way to tell a class definition from an assignment. The word has to mean exactly one thing.
Decide whether to memorise the list.
Why: You do not have to. In most development environments keywords are displayed in a different colour, so if you try to use one as a variable name, you will know.
Figure (svg): Two columns showing four Python keywords beside four ordinary names that resemble them closely
Keywords are the words the interpreter uses to parse your program, so they cannot double as names you invent. There are 33 of them, and your editor will colour them for you rather than requiring memorisation.
Verify: Type one keyword and one near-miss into an editor and compare the colours.
Why: class comes out coloured; classes does not. That colour difference is a live check you can run at any time, and it is faster and more reliable than remembering a list of thirty-three words.
Trap
A student needs somewhere to put a count of items and calls it l — a single lowercase letter, perfectly legal.
Choose a name for how fast it is to type
Why: Short names are quick, and in a three-line experiment nothing goes wrong.
Two problems arrive together. In many fonts a lowercase l is nearly indistinguishable from the digit 1, and by line forty nobody, including the author, remembers what it holds.
Programmers generally choose names that are meaningful, because a name is documentation that cannot go out of date.
Name the thing the value IS
Why: item_count says what it holds, and it says so on every line that uses it, forever.
Use underscores to join words rather than cramming them together
Why: your_name reads; yourname does not; and the underscore is there precisely for this.
There is a genuine tradeoff: long names can make complex expressions hard to read. The book says so explicitly. But the cure for that is a shorter meaningful name, not a meaningless one.
Prediction
The error message here is more informative than invalid syntax, and the reason is worth seeing.
Predict first
You type user-name = 'ada'. Why exactly does this fail?
Correct: Because Python reads the hyphen as subtraction, so the left side becomes the expression user minus name rather than a single name.
Why: The hyphen is not an illegal character in the way the at-sign is — it is a perfectly good operator that already has a job. So Python parses user-name as a subtraction, and then finds a subtraction on the left of an assignment, which is not something you can assign to. This is why the underscore exists: it is the word-joining character that is not already an operator.
Elimination
All four are legal. Only one is a good idea.
Eliminate the wrong options
A variable holds the number of seconds a task took. Which name survives?
Survives elimination: B
Why: elapsed_seconds names both the quantity and its unit, which is exactly the information a later reader needs, and it does so in two words. Naming is a genuine tradeoff between meaning and brevity, and the resolution is nearly always a short phrase rather than either extreme. Note also that including the unit in the name prevents a whole category of bug that no comment reliably prevents.
Missing information
Sometimes you cannot answer without one more fact.
Discussion prompt
Is lambda_value a legal variable name? Is lambda a legal variable name? Explain what single fact decides each, and why the two answers differ.
Hint: One of the two words is on a list.
Answer:
lambda_value is legal: letters and an underscore, no leading digit, and it is not a keyword. Keyword-ness is about the exact word, not about words containing it.
lambda on its own is a keyword and therefore illegal. It appears in the list of 33, where it names a piece of syntax that arrives in chapter 19.
The fact that decides both is membership of a fixed list — which is why the rule is checkable rather than a matter of judgement, and why your editor can colour it for you.
Section
Section 3
Concept
An expression is a combination of values, variables and operators. A value all by itself is an expression, and so is a variable. A statement is a unit of code that has an effect, like creating a variable or displaying a value.
expression — A combination of values, variables and operators, which has a value.
>>> 42
42
>>> n
17
>>> n + 25
42| Line | Why it counts as an expression | Its value |
|---|---|---|
| 42 | a value by itself | an expression, worth 42 |
| n | a variable by itself | an expression, worth 17 |
| n + 25 | values, variables and an operator | an expression, worth 42 |
Note how generous the definition of expression is. A bare 42 is an expression. A bare variable is an expression. You do not need an operator to have one.
Think Python, 2nd edition — Allen B. Downey §2.1-2.4, pp. 10-11
Picture it
The interpreter does something different with each, and it has a different word for each.
Figure (svg): Two columns contrasting expressions with statements, listing what each is and what the interpreter does with it
The two verbs are the book's, and they are worth using precisely. In general, statements do not have values — which is why an assignment displays nothing.
Worked example
For each line, decide expression or statement, and say what the interpreter does with it.
17
n
n + 25
n = 17
print(n)| Line | Which kind | What the interpreter does |
|---|---|---|
| 17 | expression | evaluated; the value 17 is displayed |
| n | expression | evaluated; whatever n refers to is displayed |
| n + 25 | expression | evaluated; the sum is displayed |
| n = 17 | statement | executed; a name is created, nothing displayed |
| print(n) | statement | executed; its effect IS the display |
Ask of each line: does this HAVE a value, or does it DO something?
Why: That single question separates the two categories reliably, and it is the question the definitions are built on.
Notice that the first three all display something.
Why: Not because they printed anything — none of them contains print — but because the interpreter displays the value of any expression you type at the prompt.
Notice that the last two are different from each other.
Why: The assignment displays nothing because its effect is invisible. The print statement displays something because displaying is precisely its effect.
Figure (svg): The state of the program after each line of Worked example classifying five lines, drawn as a ladder with one rung per traced line
Three expressions and two statements. The expressions are evaluated and their values displayed; the assignment is executed silently; the print statement is executed and its effect happens to be visible output.
Verify: Ask why 17 and print(17) look identical at the prompt.
Why: Both put 17 on the screen, by completely different routes: the first is an expression whose value the interpreter chose to display, the second is a statement whose effect is to display. They look the same here and will not in a script, which is the next section's whole point.
Discrimination
Apply the test: does this line have a value, or does it do something?
Sort into buckets
Sort each line.
Worked example
The two categories nest. Find both in this single line.
>>> minute = 59
>>> percentage = (minute * 100) / 60
>>> percentage
98.33333333333333| Part of the line | Which kind | What happens |
|---|---|---|
| minute = 59 | statement, with the expression 59 inside it | minute refers to 59 |
| (minute * 100) / 60 | an expression, evaluated first | 98.33333333333333 |
| percentage = ... | a statement, executed second | percentage refers to the result |
Find the expression inside the statement.
Why: Everything to the right of the equals sign is an expression: values, a variable and two operators.
Evaluate the expression completely before doing anything else.
Why: It has a value, 98.33333333333333, and that value is what the assignment will use.
Then execute the statement.
Why: The name percentage is pointed at that value. The statement itself has no value and displays nothing.
Figure (svg): A ladder showing the expression parenthesised minute times one hundred divided by sixty being reduced step by step to a single value which is then assigned
The line is a statement containing an expression. The expression is evaluated to 98.33333333333333, then the statement executes by pointing the name percentage at it. Nothing is displayed until you ask for the name on the following line.
Verify: Check the type of the result against the previous lesson's rule.
Why: A decimal point appeared even though 59 times 100 divided by 60 could have been left as a fraction — because a single-slash division always produces a float. The two lessons agree, which is what you want when a new idea meets an old rule.
Error analysis
Four lines from a student's notes. Two are right, two are muddled. Mark them.
Annotate
The reliable test: could this line be used somewhere a value is expected? If yes, expression. If no, statement.
Prediction
You have seen a statement containing an expression. Try it the other way round.
Predict first
What happens if you type 2 + (x = 3) at the prompt?
Correct: A syntax error, because an assignment is a statement and has no value to add to.
Why: This is the clean demonstration that the two categories are genuinely different rather than a matter of emphasis. Statements nest inside statements and expressions nest inside both, but an expression cannot contain a statement, because there would be nothing for the surrounding expression to work with. If you tried this and expected 5, you were treating assignment as though it produced a value — which is the same misunderstanding that makes a silent assignment surprising.
Matching
The book uses two different verbs deliberately. Match each to what it applies to.
Match the pairs
Why: The pairing runs across the two columns: you EVALUATE an expression, which means finding its value, and you EXECUTE a statement, which means doing what it says. Using the two verbs precisely is not pedantry — it is how you keep straight what will and will not appear on screen, which is exactly the confusion the next section is about.
Explain it to yourself
The definition seems to stretch the word. Justify it.
Discussion prompt
Explain why Python counts a lone variable name, with no operator anywhere, as an expression. What would break if it did not?
Hint: Think about where expressions are allowed to appear.
Answer:
Because it has a value: the value it refers to. That is the whole test, and a variable passes it.
If a bare variable were not an expression, you could not write print(n), or n + 25, or x = n — every one of those needs an expression in the position where n sits.
The generous definition is what makes the language compose. Anywhere a value is allowed, an expression is allowed; anything with a value is an expression; therefore names, literals and computations are all interchangeable in those positions. That single fact is why you can build up complicated lines out of simple parts.
Section
Section 4
Concept
So far you have run Python in interactive mode, which means interacting directly with the interpreter. The alternative is to save code in a file called a script and run the interpreter in script mode. By convention, Python scripts have names ending in .py.
script — A file containing a program, run all at once rather than a line at a time.
Because Python provides both modes, you can test bits of code interactively before putting them in a script. But there are differences between the two that can be confusing — and there is essentially one difference, which causes essentially all of the confusion.
Figure (svg): Two columns comparing interactive mode and script mode, showing which lines produce visible output in each
Think Python, 2nd edition — Allen B. Downey §2.1-2.4, pp. 11-11
Picture it
This is the book's own exercise, and it is worth running for real.
Figure (svg): Two columns showing the same three lines producing two lines of output at the prompt and no output in a script
Nothing is broken in the right-hand column. Python evaluated all three lines; it simply did not display any of them, because in script mode an expression all by itself has no visible effect.
Worked example
Predict both columns before advancing. Most people get the left one right and the right one wrong.
5
x = 5
x + 1| Line | Which kind | At the prompt | In a script |
|---|---|---|---|
| 5 | expression, worth 5 | 5 is displayed | nothing |
| x = 5 | statement | nothing | nothing |
| x + 1 | expression, worth 6 | 6 is displayed | nothing |
Work out the interactive column from the rule you already have.
Why: The interpreter displays the value of any expression you type. Two of the three lines are expressions, so two values appear.
Now apply the script-mode rule.
Why: In script mode an expression all by itself has no visible effect. Python evaluates the expression but does not display the result.
Notice that the program is not wrong.
Why: It computed 5, it created x, and it computed 6. All of that happened. None of it was shown, because nothing asked for it to be shown.
Figure (svg): The state of the program after each line of Worked example the book's exercise, done properly, drawn as a ladder with one rung per traced line
At the prompt: two lines of output, 5 and 6. In a script: no output at all. The code is identical and correct in both cases.
Verify: Transform each expression into a print statement and run the script again.
Why: print(5) and print(x + 1) produce the two lines that interactive mode gave for free. That the outputs then match is the proof that nothing was broken in the first place — the values were always there, and only the displaying was missing.
Prediction
Count the visible output, not the lines of code.
a = 10
b = 20
a + b
print(a + b)
a * b| Line | Which kind | Visible output |
|---|---|---|
| a = 10, b = 20 | statements | silent |
| a + b | a bare expression in a script | silent |
| print(a + b) | a print statement | displays 30 |
| a * b | a bare expression in a script | silent |
Predict first
Run this as a script. How many lines of output appear?
Correct: One — only the print statement produces visible output.
Why: Four of the five lines run perfectly and show nothing: two assignments, which are always silent, and two bare expressions, which are silent in script mode. Python computed a + b twice, once for the bare expression and once inside print, and computed a * b as well. All that work happened; only the line that asked to display anything did.
Worked example
This is the example the book uses to introduce the problem. Follow it through.
miles = 26.2
print(miles * 1.61)| Line | Which kind | What is displayed |
|---|---|---|
| miles = 26.2 | a statement | no output in either mode |
| miles * 1.61 | an expression | 42.182 at the prompt; nothing in a script |
| print(miles * 1.61) | a statement whose effect is display | 42.182 in BOTH modes |
Identify the line that behaves differently.
Why: The bare expression. It is the only line whose visibility depends on the mode.
Wrap it in print.
Why: That converts it from an expression, whose display is a courtesy of interactive mode, into a statement whose effect IS the display.
Check that the new version behaves the same everywhere.
Why: A print statement displays its argument in both modes. This is why real programs are full of print statements and interactive experiments often are not.
Figure (svg): A diagram showing an expression producing a value, and two paths from it: displayed automatically at the prompt, or displayed via print in a script
Wrapping the expression in print makes the output mode-independent. The assignment stays silent in both modes, as assignments always do.
Verify: Ask what print returns, and check whether wrapping changed the computation.
Why: The multiplication produced 42.182 either way; print did not change the arithmetic, only whether you saw it. Separating what a program COMPUTES from what it DISPLAYS is the habit this example is really teaching.
Trap
A student tests three lines at the prompt, sees the right answers, saves the same three lines as a script, runs it, and gets nothing.
Interpret silence as failure
Why: The lines worked a moment ago. Producing no output now looks like the program did not run.
The usual next move is to start changing the code, which breaks something that was working and turns one confusion into two.
Silence in script mode is the DEFAULT, not a symptom.
Check first whether the script contains any print statement
Why: If it contains none, no output is exactly what it should produce, and the code is not at fault.
Add a print around the value you want to see
Why: This is a change to what is displayed, not a change to what is computed — so it cannot break working logic.
This is worth internalising early because it is the first time a program does the right thing and looks wrong. It will not be the last, and the reflex to check what you ASKED to be shown before doubting the computation is a durable one.
Faded example
The computation is right. Only the display is missing.
Fill in the blanks
celsius = 100
fahrenheit = celsius * 9 / 5 + 32
print(fahrenheit)
Why: Writing the bare name fahrenheit on the last line would display the value at the prompt and nothing in a script, which is the trap this whole section is about. print(fahrenheit) works in both modes because displaying is its effect rather than a courtesy. Note that the two assignments above it stay exactly as they are — they were never the problem.
Comparison
Fill the blanks. The two modes are not rivals; they are used at different moments.
Comparison matrix
| Question | Interactive mode | Script mode |
|---|---|---|
| Does a bare expression show its value? | yes | no |
| How much code at a time? | one line | a whole file |
| Can you re-run it easily? | no — you retype it | yes — run the file again |
| Best for | trying something out | programs you keep |
The workflow the book recommends follows straight from this table: test bits of code interactively, then put the working pieces into a script — adding the print statements as you go.
Real world
This is not a quirk of chapter 2. It shapes how you will work for the rest of the book.
Discussion prompt
You are debugging a fifty-line script that produces a wrong final answer. Using only what this lesson gave you, describe a method for finding where it first goes wrong.
Hint: You cannot see any intermediate value unless you ask to.
Answer:
Add print statements at the points where you have an expectation — after each assignment whose value you think you can predict. Then run the script and compare each printed value with what you expected.
The first line where they disagree is where the program first departs from your understanding, and that is a much smaller thing to look at than fifty lines.
This is the whole of print-based debugging, it works in every language, and it exists precisely because script mode shows you nothing you did not ask for. Chapter 6 formalises it as incremental development, and Appendix A returns to it in earnest.
Section
Section 5
Concept
You now have all four pieces: assignment creates names, names have rules, expressions have values and statements have effects, and script mode shows only what you ask for. Reading a program means tracking all four at the same time.
minute = 59
hour = 11
percentage = (minute * 100) / 60
print(percentage)| Line | Which kind | State after |
|---|---|---|
| 1 | statement | minute -> 59 |
| 2 | statement | minute -> 59, hour -> 11 |
| 3 | statement with an expression inside | adds percentage -> 98.33333333333333 |
| 4 | statement whose effect is display | shows 98.33333333333333 |
The state column is what a state diagram draws. Notice that hour is created and never used — which is legal, silent, and exactly the kind of thing a careful reader notices.
Think Python, 2nd edition — Allen B. Downey §2.1-2.4, pp. 9-11
Picture it
Three names by the end, and only one of them was ever displayed.
Figure (svg): A state diagram showing three variables minute, hour and percentage with arrows to their values after the program has run
A variable that is created and never used is not an error, and Python will not warn you. Spotting it is a reading skill, and it often means either a line is missing or a line is redundant.
Worked example
Five lines, one name reassigned twice. Track it carefully.
total = 0
total = total + 10
total = total + 5
total = total * 2
print(total)| Line | What happens | State after |
|---|---|---|
| total = 0 | create the name | total -> 0 |
| total = total + 10 | read 0, add 10, repoint | total -> 10 |
| total = total + 5 | read 10, add 5, repoint | total -> 15 |
| total = total * 2 | read 15, double, repoint | total -> 30 |
| print(total) | display it | 30 appears |
Apply the read-then-write rule at every line.
Why: Evaluate the right-hand side using the current value, then point the name at the result. Never the other way round.
Notice that only one name ever exists.
Why: The old values are not kept anywhere. After line 3 there is no way to recover the 10 — nothing refers to it any more.
Notice that the final line is the only visible one.
Why: In a script, the four assignments show nothing. Without the print, this program would compute 30 and tell nobody.
Figure (svg): A five-rung ladder showing the value of total after each line, from zero through ten and fifteen to thirty
The program displays 30. The name total is repointed four times, and each step reads the previous value before overwriting it.
Verify: Compute the same thing as one expression and compare.
Why: (0 + 10 + 5) * 2 is 30. Agreement confirms the step-by-step reading — and the fact that both forms are available is worth noticing, since the multi-line version exists to be readable, not because it is necessary.
Invariant
Two names, and an attempt to exchange their values. Step through and watch it fail.
Step through it
At which line did the value 1 become unrecoverable, and what would you need in order to fix the swap?
The 1 was lost at the second line, before the third line ever ran. A correct swap needs somewhere to put the old value first — a third name — which is the standard fix. Chapter 12 shows a shorter way that Python provides specially for this.
Worked example
This is a correct program with a real problem. Find it.
price = 19.99
quantity = 3
total = price * quantity
total| Lines | What they are | Visible result |
|---|---|---|
| 1-3 | three statements | three names created |
| 4 | a bare expression in a script | evaluated, not displayed |
| output | nothing at all | in script mode |
Check the arithmetic.
Why: The multiplication is right and total ends up referring to 59.97. Nothing is wrong with the computation.
Check the last line.
Why: It is a bare expression. At the prompt it would display 59.97; in a script it displays nothing at all.
Identify the fix and what it does not change.
Why: Wrap it in print. That changes what is shown and leaves the three assignments and the arithmetic exactly as they are.
Figure (svg): The state of the program after each line of Worked example a program that runs and shows nothing, drawn as a ladder with one rung per traced line
The program is arithmetically correct and produces no output when run as a script, because its final line is a bare expression rather than a print statement.
Verify: Run the same four lines at the prompt and watch the bug disappear.
Why: At the prompt the last line displays 59.97, so the program appears to work. A bug that vanishes when you change how you run the code is a strong signal that the problem is about display rather than logic — which is exactly the diagnosis here.
Trap
A student writes a script that ends with a bare expression and assumes the program's answer is whatever that expression came to.
Carry over a habit from calculators and spreadsheets
Why: In both of those, the last thing you compute is the thing you see. It is a reasonable expectation to bring.
In a script it is simply not true. Python computes the value and discards it, because nothing asked for it to be kept or shown.
A program's output is exactly what it prints, and nothing else.
Decide deliberately what the program should display
Why: Then write a print statement for each of those things. Output is a design decision, not a by-product.
Treat computing and displaying as separate jobs
Why: The three assignments computed; the print displays. Keeping them separate in your head is what makes the print-based debugging of the last section possible.
This separation is why the same script can be silent when run and chatty when you add three print statements, without a single change to what it actually computes.
Prediction
Count carefully. Two of these lines are traps.
x = 2
x = x * x
x * x
print(x)| Line | What it does | State |
|---|---|---|
| x = 2 | statement | x -> 2 |
| x = x * x | statement | x -> 4 |
| x * x | bare expression: computes 16, displays nothing, changes nothing | x -> 4 |
| print(x) | displays x | shows 4 |
Predict first
Run as a script. What appears?
Correct: 4 — the third line computes 16 but neither displays it nor stores it, so print shows the value x actually has.
Why: Line 3 is the trap and it is two traps at once. It displays nothing, because a bare expression is silent in a script. And it changes nothing, because it is not an assignment — the 16 it computes is discarded immediately. So when print runs, x still refers to 4 from line 2. To keep the 16 you would need x = x * x again.
Reverse engineer
The state diagram at the end is given. Work backwards to the program.
Fill in the blanks
height = 4
width = 5
area = **height * width**
print(area)
# after running: height -> 4, width -> 5, area -> 20
Why: The final state names three variables, and only two are assigned in the visible lines, so the first missing line must create height with the value 4. The area is 20, which is 4 times 5, so the third line multiplies the two names. Reading a state diagram backwards to a program is a genuinely useful skill: it is what you do when you know what a program should end up with and have to work out how to get there.
Explain it
Rehearse the explanation before you need it, because you will need it.
Discussion prompt
A classmate has written a working ten-line script that produces no output. They are convinced Python is not running the file. In three sentences, explain what is happening and what to do — without looking at their code.
Hint: You can diagnose this without seeing the program, which is what makes it worth rehearsing.
Answer:
Say: in script mode an expression on its own displays nothing, so a script with no print statements produces no output even when every line runs correctly.
Then give them the check: search the file for the word print. If there are none, that is the whole explanation, and the fix is to add one around whatever they want to see.
Being able to diagnose this without reading the code is the point. It is the most common first-script experience there is, and the symptom — total silence from correct code — is specific enough to name the cause on sight.
Comparison
Fill the blanks from memory. Between them, these four rows explain every surprise in the lesson.
Comparison matrix
| Idea | The rule | The surprise it explains |
|---|---|---|
| assignment | evaluate the right side, then point the name at it | why n = n + 1 is not a contradiction |
| variable names | letters, digits and underscores; no leading digit; not a keyword | why class = 'x' is a syntax error |
| expressions and statements | expressions have values; statements have effects | why an assignment displays nothing |
| the two modes | a bare expression is displayed at the prompt and silent in a script | why a correct script can print nothing |
The right-hand column is the reason each rule is worth knowing. A rule that explains a surprise you have actually had is a rule you will remember.
Pattern
This is how you read any program in this book, and it does not change when the programs get longer.
Step 3 is the one that goes wrong. Evaluate the right-hand side FIRST, with the values as they are before this line runs — never with the value the line is about to produce.
Python documentation — An Informal Introduction to Python An Informal Introduction to Python
Check
Read the right-hand side before you touch the name on the left.
n = 5
n = n * 3
print(n)| Line | What happens | State after |
|---|---|---|
| n = 5 | create n | n -> 5 |
| n = n * 3 | read 5, multiply by 3, repoint | n -> 15 |
| print(n) | display | 15 |
Check your understanding
What does this script display?
Answer: B
Why: The right-hand side is evaluated first, using the value n refers to at that moment, which is 5. Five times three is fifteen, and only then is the name n pointed at the new value. Using a name on both sides of an assignment is completely ordinary, and it is how a running total is kept.
Check
Three rules. Check the proposed name against all three.
Check your understanding
Which of these is a LEGAL Python variable name?
Answer: C
Why: item_1 uses only letters, a digit and an underscore, it does not begin with a digit, and it is not a keyword. That is all three rules satisfied. The underscore is specifically there to join words in a name, which is why it is the one piece of punctuation permitted.
Check
Count only what is displayed, not what is computed.
p = 3
q = 4
p + q
print(p * q)| Line | Kind | Output |
|---|---|---|
| p = 3, q = 4 | statements | silent |
| p + q | bare expression | silent in a script |
| print(p * q) | print statement | displays 12 |
Check your understanding
Run this as a script. What appears on the screen?
Answer: B
Why: Only the print statement produces visible output. The two assignments are silent as always, and the bare expression p + q is evaluated to 7 and then discarded, because in script mode an expression by itself has no visible effect. The same four lines typed at the prompt would show 7 and then 12.
Real world
Naming a value so you can refer to it later is not a programming idea. It is an idea programming borrowed.
Discussion prompt
Find somewhere outside programming where giving something a name lets you change it in one place instead of many — a spreadsheet, a contract, a recipe, a set of instructions at work. What breaks when the name is missing and the value is written out by hand everywhere?
Hint: Think about what happens when a tax rate changes.
Answer:
A spreadsheet with the VAT rate typed into forty formulas is the everyday version. When the rate changes you must find and edit forty cells, and any one you miss is a silent wrong answer.
Put the rate in one named cell and refer to that cell everywhere, and the change is a single edit. The forty formulas did not get simpler; they got a name to point at.
This is exactly what a variable is for, and it is why the warm-up's annoyance was worth taking seriously. Naming is not a convenience — it is what makes a change in one place a change everywhere.
Commit first
Answer, then rate your confidence. This one separates two rules that are easy to blur.
Predict first
You type x = 5 at the interactive prompt, then on the next line you type x. What is displayed, in total?
Correct: Nothing, then 5 — the assignment is silent, and the bare name on the second line is an expression whose value is displayed.
Why: Two different rules are doing the work, and both are from this lesson. The assignment is a statement, so it has an effect and no value, and nothing is displayed. The lone x on the second line is an expression — the definition is generous enough to include a bare variable — so at the prompt the interpreter evaluates it and displays 5. If you predicted 5 twice, you were treating assignment as though it produced a value; if you predicted nothing twice, you were applying the script-mode rule at the prompt.
Explain it
The hardest thing to explain here is the one that sounds like a paradox.
Discussion prompt
A friend who is good at mathematics refuses to accept n = n + 1, saying it is obviously false. Convince them in under a minute, without using the word variable.
Hint: Find an everyday instruction with the same shape.
Answer:
The move that works is to find the same shape in ordinary life: your age becomes your age plus one is not a false claim, it is a description of a birthday.
Then name the difference precisely: in mathematics the equals sign asserts a relationship that holds timelessly; in Python it is an instruction with a before and an after.
Finish with the reassurance that Python does have a symbol for the mathematical meaning — a double equals sign — and it means is equal to, which is exactly what they were expecting the single one to mean. That arrives in chapter 5.
Exit ticket
One honest answer. It decides what the next lesson opens with.
Predict first
Which of these is still least solid for you?
Correct: Whichever you picked is the right answer — this one is for you, not for a mark.
Why: These settle at very different speeds. The naming rules are a five-minute fact you will never think about again once your editor colours keywords for you. Assignment order becomes automatic within a few programs. The expression-statement distinction takes longer because it is genuinely conceptual, and it keeps paying off — it is why print exists, why assignment is silent, and why the two modes differ. And the mode difference stops confusing you the first time you deliberately reproduce it, which is worth doing today.
Connect it up
One page, no code, from memory.
Draw it
Draw a diagram with two regions, one for expressions and one for statements. Put at least three examples in each. Then draw arrows showing where one can contain the other, and mark the direction that is IMPOSSIBLE with a cross. Finally, along the bottom, write what each region does at the interactive prompt and what it does in a script — four short answers in total.
Recap
Three pages, and Python can now remember things between one line and the next.
| If you remember one thing | It is this |
|---|---|
| From assignment | The equals sign is an instruction with a direction, not a claim of equality. |
| From naming | Names are documentation. Meaningful beats short, and short beats exhaustive. |
| From expressions | Has a value, or has an effect. That one question sorts every line you will meet. |
| From the two modes | Silence in a script is the default. Output is something you ask for. |
The next lesson finishes chapter 2: the precedence rules that decide what an expression means, what the plus and star operators do to strings, how to write a comment worth reading, and the three kinds of error you will spend the rest of the course telling apart.
Think Python, 2nd edition — Allen B. Downey §2.1-2.4, pp. 9-11 — everything on these slides traces back here
Want this taught 1-on-1? Alexander tutors Python — $55/session, free consultation.