Chapter 2
Variables and Input
Chapter 1 used values directly: print(4.50 + 12.00). That's fine for a
one-off, but a real script needs to hold onto a value, use it more than once,
and change it. This chapter gives values names, and takes a value from
whoever is running your script instead of writing it into the code by hand.
Naming a value
A variable is a name bound to a value. You create one with =,
assignment:
price = 4.50
print(price)
4.5price is not a container that holds 4.50 the way a box holds a book;
it's a label pointing at the value 4.50. That distinction barely matters
yet, but it matters a lot once you meet lists in Chapter 5, so it's worth
saying now.
A name can be reassigned to a completely different value at any time:
price = 4.50
print(price)
price = 12.00
print(price)
4.5
12.0Nothing links the old value to the new one. price just points somewhere
else now.
Naming rules: letters, digits, and underscores, never starting with a digit,
and Python's own words (print, if, for, and the rest) are off limits.
By convention, Python variable names are lowercase with underscores between
words, like total_spent, not TotalSpent or totalSpent. This book
follows that convention throughout.
total_spent = 4.50 + 12.00
print(total_spent)
16.5Assigning more than one name at once
Python lets you assign several names in one line, matching values to names by position:
amount, category = 4.50, "coffee"
print(amount)
print(category)
4.5
coffeeThis is called unpacking, and it works with any group of values on the right that has exactly as many items as names on the left:
amount, category, note = 4.50, "coffee"
That's ValueError: not enough values to unpack (expected 3, got 2), another
honest error rather than a guess. You'll use unpacking for real in Chapter 9,
pulling three fields out of one line read from a file.
It's also the standard way to swap two variables, without a temporary third name to hold one of them while the swap happens:
first = "coffee"
second = "transit"
first, second = second, first
print(first)
print(second)
transit
coffeef-strings
Chapter 1 built a message by concatenating with + and converting numbers
with str(). An f-string does both at once. Put an f right before the
opening quote, and anything inside {} is evaluated and inserted:
item = "coffee"
price = 4.50
print(f"{item} costs {price}")
coffee costs 4.5You can put more than a bare variable inside the braces, including a full expression:
price = 4.50
quantity = 3
print(f"{quantity} at {price} comes to {price * quantity}")
3 at 4.5 comes to 13.5f-strings are how this book builds every message from here on. str() and
+ still work, and you'll see them in other people's code, but an f-string
is shorter and doesn't need a manual str() call.
Formatting a number inside an f-string
Add a colon and a format spec after the expression to control how it's shown, without changing the underlying value:
price = 4.5
print(f"{price:.2f}")
print(f"{price:>10.2f}")
4.50
4.50.2f means "fixed-point, two digits after the decimal," which is why 4.5
prints as 4.50 here, even though Chapter 1 showed that Python drops that
trailing zero by default. >10.2f adds a minimum width of 10 characters,
right-aligned, useful for lining up a column of amounts. You'll use .2f
starting in Chapter 11, to make this book's tracker print dollar amounts
that always show two decimal places.
Taking input from a person
input() pauses a script, shows the person running it whatever prompt text
you give it, and waits for them to type a line and press enter:
name = input("What's your name? ")
print(f"Hello, {name}.")
$ python greet.py
What's your name? Ada
Hello, Ada.Why this one's shown as a listing, not run in the book
input() needs a real person at a real keyboard. This book's examples are
run for real while the book is built, with nothing attached to their input,
so a script that calls input() can't be executed here the way
print(4 + 4) can. From here on, whenever input() shows up, you'll see
it two ways: the actual script as a listing like the one above, paired
with a sample terminal session showing what a run looks like, and then the
logic that uses the result, tested for real with a stand-in value playing
the part of whatever the person typed. Keeping the "ask a person" part and
the "do something with the answer" part separate turns out to be good
practice on its own, not just a workaround, and Chapter 11 puts that to
use directly.
input() always returns a string
Whatever the person types, input() hands it back as a str, even if it
looks like a number:
raw_price = "4.50"
print(type(raw_price))
<class 'str'>(That's a stand-in for raw_price = input("Price: "), exactly as described
above: the same string input() would have returned if someone typed
4.50.)
You can't do arithmetic on it as-is, and the mistake is sneakier than an error:
raw_price = "4.50"
print(raw_price * 2)
4.504.50That's str * int, which repeats the string, not 9.0. No error, no
warning, just a wrong-looking result if you weren't expecting it. This is
worse than a crash, because nothing tells you it's wrong. Convert first,
always.
Converting with int() and float()
int() and float() convert a string to a number, if the text actually
looks like one:
raw_price = "4.50"
price = float(raw_price)
print(price)
print(type(price))
4.5
<class 'float'>raw_count = "3"
count = int(raw_count)
print(count * 2)
6If the text doesn't look like a number, conversion raises ValueError:
price = float("twelve")
That's ValueError: could not convert string to float: 'twelve'. It's an
honest error: Python is telling you exactly what it tried and exactly why it
gave up. Right now that error would crash your script. Chapter 10 shows you
how to catch it and respond instead of crashing, once you've met if and
functions, which make a good response possible. For now, just recognize the
message when you see it.
Putting it together
A tiny script for logging a coffee purchase, start to finish:
name = input("What did you buy? ")
raw_price = input("How much? ")
price = float(raw_price)
print(f"Logged: {name} for {price}")
$ python log_one.py
What did you buy? coffee
How much? 4.50
Logged: coffee for 4.5And the same logic, tested for real, with "coffee" and "4.50" standing
in for what input() would have returned:
name = "coffee"
raw_price = "4.50"
price = float(raw_price)
print(f"Logged: {name} for {price}")
Logged: coffee for 4.5Practice
Try each of these before you read the solution under it.
- Assign
item = "cappuccino"andprice = 4.20, then print"cappuccino is 4.2"using an f-string. - A stand-in for
input()gives youraw_quantity = "3". Convert it to anintand print double that number. raw_total = "12.5x"is meant to be a price but has a typo. Try converting it withfloat()and note, in a comment, what error you'd expect before running it.- Given
price = 8(a whole number, not8.00), print it formatted as a two-decimal amount with a$in front, using an f-string:$8.00.
Solutions
1.
item = "cappuccino"
price = 4.20
print(f"{item} is {price}")
cappuccino is 4.22.
raw_quantity = "3"
quantity = int(raw_quantity)
print(quantity * 2)
63. float() cannot parse a trailing letter, so this raises ValueError.
raw_total = "12.5x"
total = float(raw_total)
4. .2f formats even a plain int with two decimal places, since it's
evaluated inside the braces as part of the expression.
price = 8
print(f"${price:.2f}")
$8.00Where this leaves you
You can name a value with a variable, build a message with an f-string, and
you know why input() always hands you back a string and how to convert it,
including what happens when the text doesn't cooperate. Chapter 3 uses
comparisons and booleans to make a script choose between paths instead of
always doing the same thing.