Chapter 1

Values and Types

Every Python program is built out of values: the actual pieces of data a script works with. A price is a value. A name is a value. This chapter is about the handful of value types you'll use constantly, and about print(), the tool you'll use to look at them.

Python as a calculator

Open a terminal and type python with nothing after it. You'll land in the REPL, a prompt that reads one line, runs it, and shows you the result right away:

Terminal
$ python
>>> 4.50 + 12.00
16.5
>>> exit()

Type exit() (or press Ctrl-D on macOS/Linux, Ctrl-Z then Enter on Windows) to leave. The REPL is a scratchpad: perfect for trying one thing, not for saving work. From here on this book shows code as a script instead, exactly as you'd save and run it, and every one of those scripts is run for real while the book is built.

4.50 + 12.00
Output

Notice that printed nothing. In the REPL, typing an expression on its own shows you its result automatically. In a script, it doesn't: nothing happens to a value unless you do something with it, usually print().

print(4.50 + 12.00)
Output
16.5

+ here is an operator: a symbol that combines values into a new one. 4.50 + 12.00 is itself an expression, a piece of code that produces a value, and print() is what shows you that value.

Numbers: int and float

Python has two everyday number types. A whole number, with no decimal point, is an int:

print(3)
print(type(3))
Output
3
<class 'int'>

type() is a function that tells you a value's type, what kind of thing it is. A number with a decimal point is a float:

print(4.50)
print(type(4.50))
Output
4.5
<class 'float'>

Notice 4.50 printed as 4.5. Python doesn't remember a trailing zero you typed; a float is just its numeric value, not the exact digits you wrote.

The usual arithmetic operators all work the way you'd expect, with two worth slowing down on:

print(7 / 2)
print(7 // 2)
print(7 % 2)
Output
3.5
3
1

/ is true division and always gives you a float, even when it divides evenly. // is floor division: divide, then drop anything after the decimal point, keeping an int if both sides were int. % is the remainder, what's left over after dividing as many whole times as possible. 7 // 2 is 3 with 1 left over, which is exactly what 7 % 2 gives you.

print(2 ** 10)
Output
1024

** is exponentiation: 2 to the 10th power.

Try it

In your own script, print the result of 10 % 3 before you run it, guess the answer, then check.

A float surprise worth knowing about now

print(0.1 + 0.2)
Output
0.30000000000000004

That's not a bug in this book's example, and it's not a bug in Python. A float stores a number in binary, and most decimal fractions, including 0.1, don't have an exact binary equivalent, the same way 1/3 has no exact ending in decimal. The stored value is a tiny bit off, and usually that's invisible, until you add two of them and the tiny errors don't quite cancel out. Two things follow from this: never compare two floats with == expecting them to match exactly if either came from arithmetic, and when you need money to look right, round it for display (you'll use f"{x:.2f}" for exactly that, starting in Chapter 2), and keep the underlying calculation running on the un-rounded number for as long as possible.

Strings

Text in Python is a str, written in either single or double quotes; they mean the same thing, so pick one and be consistent:

item = "coffee"
print(item)
print(type(item))
Output
coffee
<class 'str'>

+ on strings concatenates them, joins them end to end. It does not add a space for you:

print("flat" + "white")
print("flat" + " " + "white")
Output
flatwhite
flat white

len() counts characters, including spaces:

print(len("coffee"))
print(len("flat white"))
Output
6
10

You can't concatenate a string and a number directly:

print("Total: " + 4.50)

That raises TypeError: can only concatenate str (not "float") to str. Python won't silently guess whether you meant "4.50" the text or 4.50 the number, because they're genuinely different things. You'll fix this properly with f-strings in Chapter 2; for now, str() converts a value to text explicitly:

print("Total: " + str(4.50))
Output
Total: 4.5

A few string methods you'll use constantly

A str comes with methods, functions attached to the value itself, called with a dot. You've already used one, len() isn't a method (it's a plain function), but the ones below are, and you'll reach for them often enough to learn them now rather than as you stumble into each one later.

item = "  Flat White  "
print(item.strip())
print(item.strip().lower())
print(item.strip().upper())
Output
Flat White
flat white
FLAT WHITE

.strip() removes whitespace from both ends, useful for text that came from somewhere messy, like a line read from a file. .lower() and .upper() return a new string in that case; they don't change the original.

item = "flat white"
print(item.replace("flat", "iced"))
print(item)
Output
iced white
flat white

.replace() also returns a new string rather than changing item in place. This is true of every string method: a str can't be changed after it's created, only used to build a new one. That's worth remembering alongside Chapter 5's point about lists being the opposite, changeable in place.

item = "flat white"
print(item.startswith("flat"))
print(item.endswith("latte"))
print("white" in item)
Output
True
False
True

.startswith() and .endswith() check the ends of a string. Plain in checks whether one string appears anywhere inside another, not just lists, which you'll meet properly in Chapter 5.

.split() breaks a string into a list of pieces, and .join() does the reverse, gluing a list of strings back together with a separator in between:

categories = "coffee,transit,groceries"
as_list = categories.split(",")
print(as_list)

back_together = " and ".join(as_list)
print(back_together)
Output
['coffee', 'transit', 'groceries']
coffee and transit and groceries

You'll use .split() for real starting in Chapter 9, to pull apart a line read from a file.

print() takes as many arguments as you like, separated by commas, and joins them with a space by default:

item = "coffee"
price = 4.50
print(item, price)
Output
coffee 4.5

Change the separator with sep=:

print(item, price, sep=" costs $")
Output
coffee costs $4.5

sep= is a keyword argument: you're telling print() which setting you're changing by name, rather than by position. Chapter 7 covers this properly when you write your own functions that accept them.

Practice

Try each of these before you read the solution under it.

  1. Print the result of dividing 100 by 7 with /, then with //, then the remainder with %, one per line.
  2. Given first = "flat" and second = "white", print them joined with a single space between them, without changing either variable.
  3. print() a coffee's name and its price on one line, separated by the text " -> ", using sep=.
  4. Given raw_note = " Flat White, extra hot ", clean it up to "flat white, extra hot": strip the whitespace, lowercase it, and print the result.

Solutions

1. Three separate print() calls, one per operator.

print(100 / 7)
print(100 // 7)
print(100 % 7)
Output
14.285714285714286
14
2

2. + needs the space added by hand; it never adds one for you.

first = "flat"
second = "white"
print(first + " " + second)
Output
flat white

3. sep= changes what goes between the arguments, not what comes before or after all of them.

name = "cappuccino"
price = 4.20
print(name, price, sep=" -> ")
Output
cappuccino -> 4.2

4. Chain the methods: .strip() first, then .lower() on what it returns.

raw_note = "  Flat White, extra hot  "
print(raw_note.strip().lower())
Output
flat white, extra hot

Where this leaves you

You can tell Python's core value types apart, do arithmetic including the two kinds of division, work with strings and know why you can't glue one to a number without converting it first, and use print() with more than one value. Chapter 2 gives values names that stick around, variables, and takes input from whoever is running your script.