Names and values

60 min

Listen: this lesson as a conversation

Two hosts talk the lesson through. The voices are synthetic; the script was written from this lesson and checked against it, and asserts nothing the lesson does not.

In this lesson you will learn to
  • Explain what the equals sign does, in terms of names and values rather than equality
  • Predict what each name is worth after a sequence of assignments
  • Identify the type of a value, and explain why "2" + "2" is "22"
  • Apply int() and float() to convert what input() hands back

Your programs so far run from top to bottom and forget everything, which is the whole limit on what they can do. This lesson gives them a memory. It rests on one small idea that almost everyone misreads the first time, which is what the equals sign actually does.

The equals sign is an instruction

savings = 250

Read that out loud as "savings gets 250", not "savings equals 250". It's a command, not a statement of fact. It tells Python to do two things, in a fixed order:

  1. Work out what is on the right, completely.
  2. Make the name on the left refer to that result.

Right side first, then bind. That order is all there is to it, and once you have it, the line beginners most object to stops being strange:

total = total + 5

As a claim about arithmetic it's nonsense, and people say so. As an instruction it's straightforward. Work out the right side, which needs the value total has right now, say 20, and comes to 25. Then make total refer to 25. The old value is replaced, not amended.

Predict first

Three lines run in order: a = 3, then b = a, then a = 10. What is a worth at the end, and what is b worth?

Show the answer

a is 10 and b is 3.

Line 2 does the two steps: work out the right side, which is the value 3, and bind b to it. It doesn't connect b to the name a. There's no thread running between them for line 3 to tug on. So when a is rebound to 10, b is unaffected, and still 3.

Hold on to this one, because it will matter a great deal in lesson 6, where lists behave differently and the difference has a precise cause.

That question, "what is each name worth right now", is the one you'll ask about your own code more than any other. When you can't answer it, put the program into Python Tutor, which runs it a line at a time and draws every name and value on screen.

Four kinds of value

Every value in Python has a type, and the type decides what the operators do to it. Four of them carry this whole course.

Type What it is Examples
int a whole number 250, 0, -7
float a number that can have a fraction 1.5, 0.1, -3.0, 1e6
str text, always in quotes "hello", "250", ""
bool one of exactly two values True, False

You can ask about any value with type():

>>> type(250)
<class 'int'>
>>> type("250")
<class 'str'>

Those two aren't the same thing, and the difference isn't cosmetic. 250 is a quantity you can do arithmetic with. "250" is three characters that happen to look like one.

Watch what + does to each:

>>> 2 + 2
4
>>> "2" + "2"
'22'

+ isn't being inconsistent. It means "add" for numbers and "join end to end" for text, and it picks by looking at what it's been given. So there is no arithmetic in the second line at all; it glues two characters together and hands you the result.

* makes the same kind of choice. Between two numbers it multiplies; between text and a whole number it repeats:

>>> "ab" * 3
'ababab'

That one's worth remembering, because it means a program can do something entirely reasonable with text you thought was a number, and never complain.

Getting something in from outside

input() shows a prompt, waits for the person to type a line, and hands back what they typed. Here's the part that catches everyone:

>>> reply = input("How many? ")
How many? 7
>>> type(reply)
<class 'str'>

input() always gives you a string. Always. It doesn't look at what was typed and decide. Even when the user types 7 and means seven, you get the one-character text "7".

Check yourself

A program asks age = input("How old are you? ") and the user types 41. What is age worth, and what type is it?

Show the answer

age is the string "41", not the number 41. It looks like a number and it's two characters of text. Anything you try to do with it arithmetically will fail or, worse, quietly do the wrong thing: age * 2 gives "4141" rather than 82. That's the repeating * from a moment ago, doing exactly what it was asked.

So this program is broken:

year = input("Year you were born: ")
print(2026 - year)
Year you were born: 1999
Traceback (most recent call last):
  File "/home/you/age.py", line 2, in <module>
    print(2026 - year)
          ~~~~~^~~~~~
TypeError: unsupported operand type(s) for -: 'int' and 'str'

Read that the way lesson 1 taught you: bottom line first. TypeError means the types were wrong for the operation. The message names both of them and even names the operator, -. Python's telling you it has an int on one side and a str on the other and won't guess which one you meant to convert. (The squiggles marking the failing part of the line arrived in Python 3.11, so on an older one you'll see the same error without them.)

That refusal to guess is deliberate, and Python states it as a principle: explicit is better than implicit, the second line of the Zen of Python.5 You can read the whole thing by running import this.

Notice, too, that the prompt appeared on screen before the traceback. The program ran, and then it failed. That makes this the second kind of error from lesson 1, the sort found during the run rather than before it.

The fix is to convert, with int() for whole numbers or float() for numbers with a decimal point:

year = int(input("Year you were born: "))
print(f"You turn {2026 - year} this year.")
Year you were born: 1999
You turn 27 this year.

Read int(input(...)) from the inside out. input() runs first and produces "1999". Then int() takes that and produces the number 1999.

The f before the opening quote makes it an f-string. Anything in curly brackets inside it is worked out and dropped into the text. Without the f you'd get the literal characters {2026 - year} printed, which is a mistake worth making once so you recognise it next time.

Check yourself

A user is asked for a price and types 4.50. Which conversion do you want, and what goes wrong if you pick the other one?

Show the answer

You want float("4.50"), which gives 4.5. int("4.50") doesn't round it down; it raises ValueError: invalid literal for int() with base 10: '4.50', because int() won't accept text containing a decimal point at all. We'll meet ValueError properly in the next lesson.

A number that is not quite the number

Predict first

Before you type it, what do you expect 0.1 + 0.2 == 0.3 to give?

Show the answer

False. The sum comes out as 0.30000000000000004, so the two sides really are different, and Python is reporting that honestly. The reason is below.

Now try it:

>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False

This isn't a bug in Python, and it isn't a bug in your machine. float values are stored as binary fractions, and one tenth cannot be written exactly in binary, in the same way that one third cannot be written exactly in decimal. You'd need 0.333... forever. So 0.1 is stored as something extremely close to a tenth, and the tiny gaps add up.

Three ways to live with it. Compare with a tolerance, using round():

>>> round(0.1 + 0.2, 2) == 0.3
True

Or, when the values are money, work in whole units of the smallest denomination. Count pence rather than pounds, cents rather than dollars, and use int throughout, which sidesteps the problem instead of managing it. Python also ships a decimal module that does base-ten arithmetic exactly, at the cost of being slower and wordier. Any of the three is a real answer. float for money is not.

This isn't Python's problem, either. It's the behaviour of IEEE 754 binary64, the number format nearly every language reaches for when it needs decimals, so C, Java and JavaScript all print the same thing. If you want the full story, the official documentation has a whole chapter on it.1

What people get wrong

Reading = as a claim of equality. This is where nearly every confusion in this lesson starts. It's an instruction, and the order is right side first.

Expecting b = a to keep tracking a. It doesn't, as you predicted above. It copies the value across once, and after that nothing you do to a reaches b.

Expecting input() to notice a number. It never does. If you want a number, say so with int() or float().

Expecting "2" + "2" to be 4. The + looks at what it's given. Two strings get joined.

Using is when you mean ==. This one deserves its own demonstration, because the usual advice ("is sometimes works by accident on small numbers") understates it. Put these three lines in a file, and then, separately, type the same three lines at the >>> prompt:

c = 257
d = 257
print(c is d)
Predict first

Do the file and the prompt print the same answer?

Show the answer

No. Run the file and you get True. Type exactly the same three lines at the prompt, one at a time, and you get False.

Nothing about the numbers changed. is doesn't ask whether two values are equal. It asks whether they are the same object, and whether Python bothered to reuse one object here depends on how your code was compiled, which in turn depends on whether you ran a file or typed at the prompt.

Now try it with 5 instead of 257 and you get True both ways, because CPython keeps a single shared object for every small integer and hands the same one out each time.4 So the answer moves with the size of the number and with how you ran the code. Those are implementation details you should never have to think about, and a comparison whose answer depends on them isn't a comparison you can build on.

So use == to compare values. Use is only with None, where "the same object" is what you actually mean, and where the answer never depends on how you ran the code.

Naming things

Names can hold letters, digits and underscores, and can't start with a digit. Python's convention is snake_case: lower case, words joined by underscores, so total_price rather than totalPrice or TotalPrice. It's in PEP 8, the style guide the whole Python world follows,2 and since you're choosing names anyway, you may as well choose them this way from the start.

One trap worth knowing now: don't name your own file random.py, string.py or email.py. Python looks for your file first and finds it instead of the real library, and the error you get won't make any sense at all.

Practice

Write two small programs

Take 25 minutes over these. Run each one, and when it fails, read the last line of the traceback before you change anything.

One. A unit converter. Ask for a distance in miles, then print it in kilometres and in metres. One mile is 1.609344 kilometres. Use an f-string so the output reads as a sentence rather than a bare number. You'll need float() rather than int(), and it's worth typing 1.5 at the prompt to see why.

Two. A predict-then-check. Before running this, write down what you think each print shows. Then run it.

x = 5
y = x
x = x + 1
print(x)
print(y)
print("x" + "y")
print(str(x) + str(y))

If the last two lines surprised you, that's the "two kinds of plus" idea from the middle of this lesson, and str() is the conversion going the other way from int().

Connections

Lesson 1 gave you the loop of run it and read the error. This lesson added TypeError to the two you already knew, and it arrived exactly as lesson 1 said it would, with output on screen before it, because the file parsed fine and then failed during the run.

Next comes making choices. That needs bool, which you met in the type table above and haven't used yet, and it brings the fourth error, ValueError, which is what int() raises when the text it's handed isn't a number at all. The checkpoint above has already shown you one.

Go deeper

Sources

  1. The Python Tutorial, chapter 3, "An Informal Introduction to Python", and chapter 15, "Floating-Point Arithmetic: Issues and Limitations", Python 3.14 documentation. Types, operators, and the binary-fraction explanation of 0.1 + 0.2.
  2. PEP 8, Style Guide for Python Code. The snake_case naming convention.
  3. Allen B. Downey, Think Python, 3rd edition, 2023, chapter 2, "Variables and Statements". Free online under CC BY-NC-SA 4.0. Linked, not adapted.
  4. All code output in this lesson was run on CPython 3.14.7 and pasted from the terminal, including the TypeError traceback and the is comparison giving different answers in a file and at the prompt.
  5. PEP 20, The Zen of Python, Tim Peters, 19 August 2004. "Explicit is better than implicit", the second of its nineteen lines.

Check your understanding

This lesson has a 5-question quiz. Pass it and the questions come back on a schedule in Review, so what you learned stays learned. Your progress is saved in your browser; no account needed.