Types, and converting between them
Python knows the difference between the number 5 and the text "5". They look identical printed on a screen and they behave nothing alike, and almost every confusing early error comes from one being where the other was expected.
print(5 + 5)
print("5" + "5")
10 55
Same operator, same-looking values, two completely different jobs. Between
numbers + adds; between strings it joins.
The four types you start with
print(type(7))
print(type(7.5))
print(type("seven"))
print(type(True))
<class 'int'> <class 'float'> <class 'str'> <class 'bool'>
int is a whole number. float is a number with a decimal point. str is
text. bool is True or False — capitalised, unlike most languages, and a
common source of typos.
type() is the tool for finding out what you actually have, and it is the
first thing to reach for when a value is not behaving.
int and float are not interchangeable
print(7 / 2)
print(7 // 2)
print(7 % 2)
print(type(6 / 2))
3.5 3 1 <class 'float'>
/ always produces a float, even when the answer is whole — 6 / 2 gives
3.0, not 3. // is floor division, which divides and throws away the
remainder. % gives that remainder.
That last line catches people. If a program needs a whole number — a row
index, a count of pages — / will hand it a float and something downstream
will object. // or int() is what you want.
Converting on purpose
Each type name doubles as a conversion function.
print(int("42"))
print(float("42"))
print(str(42))
print(int(7.9))
print(float(7))
42 42.0 42 7 7.0
int(7.9) gives 7, not 8. It truncates — chops the decimal off —
rather than rounding. When you want rounding, say so with round():
print(int(7.9))
print(round(7.9))
print(round(7.4))
print(round(2.5))
print(round(3.5))
7 8 7 2 4
Those last two are not a mistake. Python uses banker's rounding: an exact half goes to the nearest even number. It exists so that rounding a long column of figures does not drift upwards, and it surprises everyone once.
Conversion that fails, loudly
print(int("42"))
print(int("forty two"))
Nothing is printed for the second line, because the program stops:
ValueError: invalid literal for int() with base 10: 'forty two'
This is Python being helpful. JavaScript would hand back a quiet NaN that
poisons every later calculation; Python refuses at the point of the mistake and
tells you the exact string it could not read. A crash on line 2 is much cheaper
to fix than nonsense on a receipt.
int("42.5") fails too, for the same reason — "42.5" is not a whole number.
Convert to float first if that is what you meant.
input() always gives you a string
This is the one that catches every beginner, and it catches them the same way.
age = "16"
print(type(age))
print(age + 1)
That last line stops the program:
TypeError: can only concatenate str (not "int") to str
input() returns a string. Always. Even when the person typed digits and
nothing else. So this — which looks completely reasonable — does not work:
age = input("Your age: ")
next_year = age + 1 # TypeError
The fix is to convert as the value arrives, not later:
age = int(input("Your age: "))
next_year = age + 1 # fine
Doing it on the same line means every use afterwards is already a number. Getting input in a browser works a little differently on this site, which the input lesson covers.
Notice also that Python raised a TypeError rather than guessing. That is the
deliberate difference from JavaScript, where "16" + 1 silently produces
"161".
Truthiness
Any value can be used where Python expects a condition. The values that count as false are few:
print(bool(0))
print(bool(""))
print(bool([]))
print(bool(None))
print(bool("0"))
print(bool(-1))
print(bool(" "))
False False False False True True True
Zero, the empty string, the empty list and None are falsy. Everything else is
truthy, including the string "0" and a string containing only a space.
The practical warning is the same one every language has: if count: asks
whether count is truthy, not whether it exists. A genuine count of zero takes
the else branch, which is almost never what you meant. Use
if count is not None: when zero is real data.
None is not zero and not empty
nothing = None
print(nothing)
print(type(nothing))
print(nothing is None)
None <class 'NoneType'> True
None means "no value here". It is Python's single answer to the question
JavaScript splits between null and undefined.
Compare it with is, not ==. is None is the idiom, it reads well, and it
cannot be fooled by a class that has redefined equality.
Mixing types
Python allows arithmetic between int and float, quietly widening to float:
print(3 + 0.5)
print(type(3 + 0.5))
print(True + 1)
3.5 <class 'float'> 2
That last line is real: bool is a subclass of int, with True equal to 1.
It means sum([True, False, True]) counts how many are true, which is
occasionally useful and mostly a curiosity.
What Python will not do is mix strings with numbers:
print("Total: " + str(450))
Total: 450
The str() is required. Leave it out and you get a TypeError — which is why
f-strings, which convert automatically, are the better habit:
total = 450
print(f"Total: {total}")
Total: 450
The rule worth carrying
Convert at the boundary. The moment a value arrives from outside your
program — from input(), from a file, from a web form — turn it into the type
you actually mean, on that line. Everything after it then works with real
numbers and real text, and type() is there for the times it still does not.
Next: comments and readable code.
Prefer learning with a teacher?
WasiLearn Academy runs small-group classes covering this material, online and in Karachi.
See the classes