Values, types and names · about 35 min

Converting between types

Why this matters

Data arrives as text: from input(), files, command-line arguments, network requests. Your program needs numbers, booleans and other types to compute with, and then text again to print results. Converting correctly, and knowing which conversions fail or silently lose information, is everyday work. This lesson also introduces repr, the tool that shows you what a value really is when printing it is not enough.

Conversion means making a new object

Python never changes the type of an existing object. "Converting" means calling a type to build a new object from an old one:

text = "42"
number = int(text)
print(text, type(text).__name__)
print(number, type(number).__name__)
42 str
42 int

text still refers to the string. int(text) read its characters and produced a separate int object. The types int, float, str and bool are callable, and calling one is how you construct values of that type.

To int

print(int("42"))
print(int("  -7\n"))     # whitespace around is ignored
print(int("1_000"))      # underscores between digits are allowed
print(int(3.99))         # float -> int truncates toward zero
print(int(-3.99))
print(int(True))
42
-7
1000
3
-3
1

int() of a string is strict: int("3.5"), int("12abc") and int("") all raise ValueError. That strictness is a feature: bad input fails loudly rather than becoming a wrong number.

Other bases

The second argument to int is the base the text is written in:

print(int("1010", 2))    # binary
print(int("ff", 16))     # hexadecimal, case does not matter
print(int("17", 8))      # octal
print(int("0x1F", 16))   # a 0x prefix is accepted when it matches the base
print(int("0b101", 0))   # base 0: read the prefix to decide
10
255
15
31
5

In base 16 the digits a-f mean 10-15. Bases from 2 to 36 are allowed. The reverse conversion (int to binary or hex text) uses bin(), hex() and oct(), covered with bitwise operators in the next module.

To float

print(float("3.14"))
print(float("  2 "))
print(float("1e-3"))
print(float(7))
print(float("inf"), float("nan"))
3.14
2.0
0.001
7.0
inf nan

float() accepts anything that looks like a decimal or scientific-notation number. Converting a large int to float may lose precision, since a float has only 53 bits of mantissa: float(2**53 + 1) is 9007199254740992.0, which is 2**53, off by one.

To str

str(x) gives the "informal", human-readable text for a value. It is what print uses:

print(str(42) + "!")
print(str(3.0))
print(str(None))
print(str(True))
42!
3.0
None
True

Converting to str never fails for built-in types. You need it when joining with +, because "Age: " + 36 is a TypeError.

To bool: truthiness

bool(x) asks "is x considered true?". The rule for built-in types: zero and empty things are false, everything else is true.

FalseTrue
False, NoneTrue
0, 0.0any other number, e.g. -1, 0.001
"" (empty string)any non-empty string, even "False", "0", " "
empty containers [], {}non-empty containers
print(bool("False"))
print(bool(""))
True
False

bool("False") is True because the string is non-empty; bool does not interpret the words. To turn user answers into booleans, compare text: answer == "yes". This "truthiness" is what if and while use, which the next module explores.

str versus repr

Every object has two text forms:

s = "tab\there"
print(str(s))
print(repr(s))
print(repr(42), repr(3.5), repr(None))
print(repr("it's"))
tab    here
'tab\there'
42 3.5 None
"it's"

For numbers and None, both forms coincide. For strings, repr adds quotes and shows escape sequences, so invisible characters become visible. That makes repr the best debugging tool for text: when two strings "look the same" but == says False, print their reprs and you will spot the trailing space, the tab or the \r from a Windows file. repr chooses double quotes when the string contains a single quote, as with "it's".

Chains of conversions

Conversions can be chained; read them inside out:

text = "3.7"
whole = int(float(text))     # "3.7" -> 3.7 -> 3
nearest = round(float(text)) # "3.7" -> 3.7 -> 4
print(whole, nearest)
3 4

Watch out for float error when scaling, a classic in money calculations:

print(19.99 * 100)
print(int(19.99 * 100))
print(round(19.99 * 100))
1998.9999999999998
1998
1999

int() truncated the almost-1999 down to 1998, losing a cent. round() gives the intended value.

Common mistakes

Recap

Going further: read help(int) in the REPL for the full rules of int(x, base). Try ascii("café") and compare it with repr("café").

Exercises

Exercise 1 · quiz

int() of a decimal string

What happens with int("3.7")?

Answer
  • It raises ValueError

int() given a string accepts only an optional sign and digits (plus surrounding whitespace and underscores between digits). "3.7" is not a valid integer literal, so you get ValueError: invalid literal for int() with base 10: '3.7'. Given a float, int(3.7) truncates to 3. To go from the string, convert twice: int(float("3.7")).

Exercise 2 · quiz

bool() of a string

Select all expressions that evaluate to True.

Answer
  • bool("False")

  • bool(" ")

  • bool(-1)

bool() does not read the text: any non-empty string is true, even "False" and " " (a space is a character). Numbers are false only when zero, so -1 is true and 0.0 false. None is false. To interpret user input like "yes"/"no" you must compare the text yourself.

Exercise 3 · write code

Read numbers in other bases

Read three lines: a binary number (digits 0 and 1), a hexadecimal number (digits 0-9 and a-f, either case) and an octal number (digits 0-7), all without prefixes. Print their decimal values and their sum, exactly like this. For inputs 1010, ff, 17:

binary 1010 = 10
hex ff = 255
octal 17 = 15
sum = 280

Use int(text, base).

File: main.py

Starting point

b = input()
h = input()
o = input()

Example

input

1010
ff
17

expected output

binary 1010 = 10
hex ff = 255
octal 17 = 15
sum = 280

Example

input

11111111
CAFE
777

expected output

binary 11111111 = 255
hex CAFE = 51966
octal 777 = 511
sum = 52732
Hint 1

int("ff", 16) is 255.

Hint 2

Keep the original text for the label and the converted number for the value.

Reference solution
b = input()
h = input()
o = input()
bv = int(b, 2)
hv = int(h, 16)
ov = int(o, 8)
print("binary", b, "=", bv)
print("hex", h, "=", hv)
print("octal", o, "=", ov)
print("sum =", bv + hv + ov)

Exercise 4 · write code

See what you really got

Input text can hide things: trailing spaces, tabs, quote characters. Read one line and print it twice: first with str (what print normally shows) between square brackets, then its repr. For the input line say "hi" followed by a tab character, the output is:

[say "hi"    ]
'say "hi"\t'

(The first line contains a real tab before the ]; the second line shows the escape \t as two characters.)

File: main.py

Starting point

line = input()
print("[" + line + "]")

Example

input

say "hi"

expected output

[say "hi"	]
'say "hi"\t'

Example

input

  padded

expected output

[  padded  ]
'  padded  '
Hint 1

repr(x) returns the programmer's representation of x as a string.

Hint 2

Printing repr(line) shows the quotes and escape sequences.

Reference solution
line = input()
print("[" + line + "]")
print(repr(line))

Exercise 5 · write code

Mixed conversions

Read a price in dollars as text (for example 19.99) and a whole-number quantity. Compute the total in cents as an integer, rounding to the nearest cent, and print exactly (for 19.99 and 3):

total cents: 5997
total dollars: 59.97

The second line is the cents divided by 100 (true division). Hint: the price times 100 is a float that may not be exact (19.99 * 100 is 1998.9999999999998), so use round() before multiplying by the quantity.

File: main.py

Starting point

price = float(input())
qty = int(input())
cents = int(price * 100) * qty
print("total cents:", cents)
print("total dollars:", cents / 100)

Example

input

19.99
3

expected output

total cents: 5997
total dollars: 59.97

Example

input

0.29
1

expected output

total cents: 29
total dollars: 0.29
Hint 1

Try print(19.99 * 100) and print(int(19.99 * 100)) to see the problem.

Hint 2

int() truncates; round() goes to the nearest whole number and returns an int.

Reference solution
price = float(input())
qty = int(input())
cents = round(price * 100) * qty
print("total cents:", cents)
print("total dollars:", cents / 100)