PYTH-101 · Lesson 2 of 12 · 27 min

Values, types and variables

▶ Video coming soon A video version of this lesson is on the way.

Every program works with values: the number of bags on a shelf, the price of a latte, the name of a coffee, whether the roaster is switched on. Before a program can calculate anything, it needs a way to hold those values and refer to them. This lesson covers the kinds of value Python works with, called types, and the names you give values so that you can use them again, called variables. By the end you will be able to store Ridgeline's stock figures in well-named variables, convert between text and numbers, and read a value typed in by a person.

These ideas look simple, and in a sense they are, but they shape everything that follows. Most beginner bugs come from a value being a different type from the one the programmer assumed, or from a variable holding a different value from the one they thought. Time spent understanding exactly what a variable is will repay itself in every later lesson.

Values and types

A value is a single piece of data. The number 42 is a value; so is the text Sunrise Blend, and so is the price 18.50. Every value in Python has a type, which decides what the value can do. You can multiply two numbers, but multiplying two pieces of text makes no sense; you can make text uppercase, but not a number. Python checks the type of each value when it uses it, and that check is the source of many helpful error messages.

Four types cover almost everything in this course's early lessons. An int, short for integer, is a whole number such as 42, 0 or -7. A float, short for floating-point number, is a number with a decimal point, such as 18.50 or 0.15. A str, short for string, is text, written inside quotation marks, such as 'Ethiopia Guji'. A bool, short for Boolean, is one of just two values, True or False, and is used for yes-or-no facts such as whether a coffee needs reordering. Python also has a special value, None, that means no value at all; it appears when something has not been set yet or a function has nothing to give back.

The basic types used in the first half of the course
TypePython nameRidgeline examplesTypical use
Integerint42 bags, 340 grams, 10 pointsCounting things
Floating-point numberfloat18.50, 0.15, 10.2 kgMeasurements and money in simple programs
Stringstr'Sunrise Blend', 'RC-101', 'B-0412'Names, codes and messages
BooleanboolTrue, FalseYes-or-no facts such as in stock or not
NoneNoneTypeNoneA value that has not been set

The built-in function type tells you the type of any value. It is a useful tool when a program behaves strangely: printing the type of a suspicious value often reveals that it is a string of digits rather than a number, or a float where you expected an integer.

Asking Python for the type of each value
print(type(42))
print(type(18.50))
print(type("Sunrise Blend"))
print(type(True))
print(type(None))
print(type("42"))
Output
<class 'int'>
<class 'float'>
<class 'str'>
<class 'bool'>
<class 'NoneType'>
<class 'str'>

Look at the last line. The value '42' in quotation marks is a string that happens to contain digits, not a number. To Python, '42' and 42 are entirely different things, as different as the word forty-two written on a sticky note and a pile of forty-two coffee bags. Keeping that difference in mind will save you a great deal of confusion when you start reading input from people and files, which always arrives as text.

Variables: names for values

A variable is a name that refers to a value. You create one with an assignment statement, which has a name on the left, an equals sign, and an expression on the right. Python works out the value of the right-hand side first, then attaches the name on the left to that value. After that, wherever you write the name, Python uses the value.

Storing one coffee in variables and using them in calculations
sku = "RC-101"
name = "Sunrise Blend"
price = 18.50
stock = 42
reorder_point = 10
print(name, "costs", price, "and there are", stock, "bags")
print("Stock value:", price * stock)
print("Bags above the reorder point:", stock - reorder_point)
Output
Sunrise Blend costs 18.5 and there are 42 bags
Stock value: 777.0
Bags above the reorder point: 32

The equals sign in Python does not mean 'is equal to' in the mathematical sense. It is an instruction: make this name refer to this value. Reading it as 'gets' or 'is set to' helps. That is why a line like stock = stock - 3, which would be nonsense as an equation, is perfectly sensible in a program: work out the current stock minus three, then make stock refer to the result.

Three name tags on the left, labelled name, price and stock, each with an arrow pointing to a box on the right holding a value: the text Sunrise Blend, the float 18.5 and the integer 42. A second panel shows the same stock tag after the assignment stock = stock - 3, now pointing to a new box holding 39, while the old box holding 42 is faded.
A variable is a name tag attached to a value; assignment moves the tag to a new value

A good mental picture, shown in the figure, is that a variable is a name tag tied to a value, rather than a box that contains it. When you assign a new value to the name, the tag moves to the new value. The difference matters later, when two names can be tied to the same list, but even now it explains why assignment never changes the old value: it just points the name somewhere else.

Once Theo sells three bags of Sunrise Blend and Kai roasts a fresh batch of thirty, the stock changes. The program below follows those events. Press Edit and run, then try changing the number of bags sold to see the final figure change.

Updating a variable as the day goes on
stock = 42
print("Opening stock:", stock)
stock = stock - 3      # three bags sold online
print("After online orders:", stock)
stock = stock + 30     # a fresh batch is bagged
print("After roasting:", stock)
stock -= 5             # five bags sold in the cafe
print("Closing stock:", stock)
Output
Opening stock: 42
After online orders: 39
After roasting: 69
Closing stock: 64

The last update uses an augmented assignment, -=, which is shorthand for stock = stock - 5. Python has the same shorthand for the other arithmetic operators, such as += and *=. These short forms are common in real code, especially for running totals and counters, so it is worth getting used to them early.

Naming rules and conventions

Python has a few strict rules for variable names. A name may contain letters, digits and underscores, but it must not begin with a digit and it must not contain spaces or punctuation. Names are case-sensitive, so stock, Stock and STOCK are three different variables. A name cannot be one of Python's reserved keywords, such as if, for, while, def, class, True or None, because those words already have a meaning in the language.

Legal and illegal variable names
NameAllowed?Why
bags_in_stockYesLetters and underscores
price2YesA digit is fine after the first character
2nd_priceNoStarts with a digit
reorder pointNoContains a space
roast-weightNoA hyphen means subtraction
classNoA reserved keyword
StockYes, but avoidLegal, but capitalized names are used for classes

Beyond the rules, Python programmers follow a style guide called PEP 8. It recommends lowercase names with words separated by underscores, a style known as snake_case: roasted_kg rather than roastedKg or RoastedKG. Names written entirely in capitals, such as REORDER_POINT, signal a constant, a value that is set once and not meant to change while the program runs. Python does not enforce this; it is a message from one programmer to another.

The most important convention is not in any rulebook: choose names that say what the value means. A variable called x tells the reader nothing, while bags_sold_today tells them almost everything. Long names cost a little typing; unclear names cost hours of puzzling later. Single letters are fine in a few traditional places, such as i for a loop counter, but for anything that represents a real quantity, spell it out, and include the unit when there could be doubt, as in green_kg or roast_minutes.

Numbers in more detail

Integers in Python can be as large as you like; Python simply uses more memory for very large numbers. You can write large integers with underscores to make them readable, as in 1_000_000, and Python ignores the underscores. Floats are different. They are stored in a fixed amount of memory using binary fractions, which means most decimal fractions cannot be represented exactly. The result is small rounding errors that surprise everyone the first time.

Floats are approximate, integers are exact
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
print(round(0.1 + 0.2, 2))
print(18.50 * 3)
print(1_000_000 + 1)
print(7 / 2, type(7 / 2))
Output
0.30000000000000004
False
0.3
55.5
1000001
3.5 <class 'float'>

The value 0.30000000000000004 is not a bug in Python; every language that uses standard floating-point numbers behaves the same way. For everyday calculations the error is far too small to matter, and rounding the result for display, with round or with the formatting tools in lesson 4, hides it. It does matter when you compare floats for exact equality, so avoid testing whether two floats are exactly equal. For money in real accounting software, programmers use whole numbers of cents or Python's decimal module; Anita's bookkeeping tools in later courses will do that, while this course uses floats to keep the examples simple.

The last line shows another point: dividing two integers with / always gives a float, even when the answer is a whole number, so 8 / 2 is 4.0. Lesson 3 introduces the // operator for whole-number division and explains when to use each.

Converting between types

Values can be converted from one type to another with functions named after the types: int, float, str and bool. Converting is often essential. Text read from a keyboard or a file is always a string, so before you can do arithmetic with it you must convert it to a number. Going the other way, you sometimes need to turn a number into a string to join it to other text.

Converting strings to numbers and numbers to strings
bags_text = "42"
bags = int(bags_text)
print(bags + 3)
price = float("18.50")
print(price * 2)
print(int(19.99))            # int() drops the fraction, it does not round
print(round(19.99))
label = "Bags: " + str(bags)
print(label)
print(bool(0), bool(42), bool(""), bool("Kai"))
Output
45
37.0
19
20
Bags: 42
False True False True

Two details deserve attention. First, int applied to a float throws away the fractional part rather than rounding, so int(19.99) is 19; use round if rounding is what you want. Second, bool turns zero, empty strings and None into False and almost everything else into True. That rule, called truthiness, becomes useful in lesson 5.

Not every conversion succeeds. Asking for int('forty-two') or int('18.50') makes no sense to Python, so it stops with a ValueError. The message is clear about what went wrong, and lesson 11 shows how a program can catch such errors and ask again instead of stopping.

A failed conversion stops the program with a ValueError
print(int("18.50"))
Traceback (most recent call last):
  File "convert.py", line 1, in <module>
    print(int("18.50"))
          ^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: '18.50'

Reading input from a person

So far every value has been written into the program itself, which is called hard-coding. Real tools let people supply values while the program runs. The input function displays a prompt, waits for the person to type a line and press Enter, and returns what they typed as a string. To use the answer as a number, convert it.

A small program that asks for three values (the input lines are shown below)
name = input("Coffee name: ")
bags = int(input("Bags in stock: "))
price = float(input("Price per bag: "))
print(name, "stock is worth", bags * price)
Output
Coffee name: Colombia Huila
Bags in stock: 27
Price per bag: 19.75
Colombia Huila stock is worth 533.25

When you run this listing in the page, the editor shows an Input box: type one answer per line, such as Colombia Huila, 27 and 19.75, and Python reads them in order as if you had typed them at the keyboard. In a terminal, the program pauses at each prompt instead. See how the int and float calls wrap the input calls: Python runs input first, gets a string, and passes it straight to the conversion. If you forget the conversion, bags * price fails, because Python will not multiply a string by a float.

A common slip is to compare or add input without converting it. If two people each type 3 and the program adds the raw answers, the result is '33', because adding two strings joins them. The next lesson explains why; the cure is always to convert first.

Worked problem

Planning a roast-yield calculator

Kai wants a script that asks for the green weight and roasted weight of a batch in kilograms and prints the weight lost in kilograms and as a fraction of the green weight. Plan the variables and conversions, then check it with a 12 kg batch that roasts to 10.2 kg.

Show solution
  1. Input: two numbers typed by Kai, each read with input and converted with float, because weights have decimals.
  2. Variables: green_kg and roasted_kg for the inputs, lost_kg for the difference and loss_fraction for lost_kg / green_kg.
  3. Processing: lost_kg = green_kg - roasted_kg, then loss_fraction = lost_kg / green_kg.
  4. Output: print both, rounding the fraction to three places with round(loss_fraction, 3).
  5. Check by hand: 12 - 10.2 = 1.8 kg lost, and 1.8 / 12 = 0.15, which matches the usual 15 out of 100 loss in roasting. The float result for lost_kg may print as 1.8000000000000007, so round it to 2 places as well.

Answer: The program prints 1.8 kg lost and a loss fraction of 0.15.

The roast-yield calculator with the inputs fixed so it runs without typing
green_kg = 12.0       # in the real program: float(input("Green kg: "))
roasted_kg = 10.2     # in the real program: float(input("Roasted kg: "))
lost_kg = green_kg - roasted_kg
loss_fraction = lost_kg / green_kg
print("Unrounded loss:", lost_kg)
print("Weight lost (kg):", round(lost_kg, 2))
print("Loss as a fraction:", round(loss_fraction, 3))
Output
Unrounded loss: 1.8000000000000007
Weight lost (kg): 1.8
Loss as a fraction: 0.15

Try it yourself

Variables for a new coffee

Ridgeline is adding Guatemala Antigua to the list. Create four variables: sku set to the string RC-107, name set to Guatemala Antigua, price set to the float 20.75 and stock set to the integer 24. Then print the stock value, price * stock, which should be 498.0.

# Create the four variables here

print(price * stock)

How Python stores values

Behind the scenes, every value in a running Python program is an object stored somewhere in the computer's memory, and every variable is a reference to one of those objects. The built-in function id returns a number that identifies an object while the program runs; two names that refer to the same object have the same id. You will rarely need id in practice, but it makes the name-tag picture concrete.

Two names, one value, until one of them is reassigned
stock = 42
also_stock = stock
print(id(stock) == id(also_stock))
stock = stock + 1
print(stock, also_stock)
print(id(stock) == id(also_stock))
Output
True
43 42
False

After also_stock = stock, both names are tied to the same value, 42. When stock is reassigned to 43, only the stock tag moves; also_stock still refers to 42. Numbers, strings and Booleans can never be changed in place, a property called being immutable, so this behaviour is always safe with them. Lists, which arrive in lesson 8, can be changed in place, and there the shared-tag picture becomes essential.

Python is also dynamically typed: a variable has no fixed type of its own, so the same name can refer to an int now and a string later. That flexibility is convenient but can hide mistakes, which is why many teams add optional type hints, a notation covered in PYTH-102, and why clear names matter so much.

Try it yourself

Total from typed input

Theo types two numbers: the bags sold online and the bags sold in the cafe. The starter reads them with input but prints the wrong answer, because input always gives back strings. Fix the program so that it prints the total as a number.

The Input box already holds 3 and 5, so the correct output ends with Total bags sold: 8.

online = input("Online: ")
cafe = input("Cafe: ")
print("Total bags sold:", online + cafe)

Common mistakes

  • MistakeDoing arithmetic with input before converting it, so '3' + '5' gives '35'.

    InsteadConvert with int() or float() as soon as the value is read: bags = int(input(...)).

  • MistakeReading = as a test of equality and writing 42 = stock.

    InsteadAssignment always has the name on the left: stock = 42. The test for equality is ==, covered in lesson 3.

  • MistakeExpecting int(19.99) to give 20.

    Insteadint() drops the fraction; use round(19.99) to round to the nearest whole number.

  • MistakeComparing two floats for exact equality, such as 0.1 + 0.2 == 0.3.

    InsteadRound both sides first, or check whether the difference is very small.

  • MistakeUsing vague names such as x, data2 or temp for real quantities.

    InsteadName variables for what they mean, with units where useful: roasted_kg, bags_sold_today.

  • MistakeQuoting numbers by accident, as in stock = "42".

    InsteadWrite numbers without quotation marks unless you really want text.

Summary and key terms

  • Every value has a type; the basic ones are int, float, str and bool, plus the special value None.
  • type(value) shows the type, which is the first thing to check when a program misbehaves.
  • An assignment such as stock = 42 makes a name refer to a value; the right-hand side is worked out first.
  • Variables can be reassigned; augmented assignments such as stock -= 5 update them in place of a longer line.
  • Names use letters, digits and underscores, cannot start with a digit and are case-sensitive; PEP 8 recommends snake_case.
  • Floats are approximate; round for display and avoid exact comparisons of floats.
  • int(), float(), str() and bool() convert between types; input() always returns a string.
value
A single piece of data, such as 42 or Sunrise Blend.
type
The kind of a value, which decides what operations it supports.
variable
A name that refers to a value.
assignment
A statement that makes a name refer to the value of an expression.
integer (int)
A whole number of any size.
floating-point number (float)
A number with a fractional part, stored approximately.
string (str)
A sequence of characters: text.
Boolean (bool)
The type with only two values, True and False.
type conversion
Turning a value of one type into the corresponding value of another type.
immutable
Unable to be changed in place; ints, floats, strings and Booleans are immutable.

Practice problems

Work each problem on paper first, then reveal the answer to check.

  1. What does type(10.2) return, and what does type("10.2") return?

    Show answer

    float for the first, str for the second, because the quotation marks make it text.

  2. After a = 5, b = a, a = a + 1, what are a and b?

    Show answer

    a is 6 and b is still 5; reassigning a moves only the a tag.

  3. Which names are illegal: roast_kg, 3bags, total-sales, Price, for?

    Show answer

    3bags (starts with a digit), total-sales (hyphen) and for (a keyword). Price is legal but not PEP 8 style for a variable.

  4. What does int(float("7.9")) give?

    Show answer

    7, because float("7.9") is 7.9 and int() drops the fraction.

  5. Why does print("Bags: " + 42) fail, and how do you fix it?

    Show answer

    A string cannot be joined to an int with +. Use str(42), or print("Bags:", 42).

  6. Write one line that reads a price typed by the user and stores it as a float.

    Show answer

    price = float(input("Price: "))

Lesson quiz · 5 questions

Score 60% or more to complete this lesson.

Take the quiz