CertGrid CertGrid
Concepts·Certified Entry-Level Python Programmer

Python Type Casting and Floating Point Accuracy

The second half of objective 1.4: converting between types. `int()`, `float()`, `str()` and `bool()` are four functions with a small number of sharp edges - `int("3.5")` raises where `int(3.5)` does not, and `int()` truncates where `round()` does something stranger. Float accuracy is the other half: `0.1 + 0.2` is not `0.3`, and the exam knows it.

Language Fundamentals Guide 8 of 26 Beginner

Written against the versions above. Written against **Python 3.14**. The rounding behaviour here has been the same since Python 3.0 and is a genuine Python 2 to 3 change: Python 2's `round(2.5)` was 3. Anything showing 3 is Python 2 material.

One machine, and any shell with Python 3 will do - these exams test the language, not a distribution.
Server NameIP AddressOSRolesCPURAMHDD
RUNNER01192.168.0.27Ubuntu 26.04 LTSPython 3.14.4 - the only machine this path needs2 Core4 GB50 GB

Before you start

  1. The four conversion functions

    int(), float(), str() and bool() are the conversions the syllabus names. Each takes almost anything and produces its own type - and each has rules worth knowing exactly.

    Ten conversions below. repr() is used on the str() results so you can see that they really are strings.

    bash Example session
    cat > ~/py/casts.py <<'PY'print("int(3.9)      =", int(3.9))print("int(-3.9)     =", int(-3.9))print("int('42')     =", int("42"))print("int('  42  ') =", int("  42  "))print("int(True)     =", int(True))print("float('3.14') =", float("3.14"))print("float(3)      =", float(3))print("float('1e3')  =", float("1e3"))print("str(3.0)      =", repr(str(3.0)))print("str(True)     =", repr(str(True)))PYpython3 ~/py/casts.pyint(3.9)      = 3int(-3.9)     = -3int('42')     = 42int('  42  ') = 42int(True)     = 1float('3.14') = 3.14float(3)      = 3.0float('1e3')  = 1000.0str(3.0)      = '3.0'str(True)     = 'True'

    Expected result3 and -3 from the floats, 42 twice, and '3.0' in quotes.

    Success conditionYou can predict the value and type of any of these conversions.

  2. What the conversions refuse, and with which exception

    The failures are as examinable as the successes, and they are all ValueError - the type was acceptable, the *value* was not.

    The first one is the trap: int() will not read a decimal point out of a string, even though it happily truncates a float.

    bash Example session
    python3 -c 'print(int("3.5"))'Traceback (most recent call last):  File "<string>", line 1, in <module>    print(int("3.5"))          ~~~^^^^^^^ValueError: invalid literal for int() with base 10: '3.5'[exit 1]python3 -c 'print(int(""))'Traceback (most recent call last):  File "<string>", line 1, in <module>    print(int(""))          ~~~^^^^ValueError: invalid literal for int() with base 10: ''[exit 1]python3 -c 'print(float("abc"))'Traceback (most recent call last):  File "<string>", line 1, in <module>    print(float("abc"))          ~~~~~^^^^^^^ValueError: could not convert string to float: 'abc'[exit 1]python3 -c 'print(int(float("3.5")))'3

    Expected resultThree ValueErrors, then 3 from the two-step conversion.

    Success conditionYou can name the exception and the fix for each refusal.

  3. Truthiness, in full

    bool() never raises - every object in Python has a truth value. The rule is short: zero, empty, and None are false; everything else is true.

    Twelve values below, including the three that catch people.

    bash Example session
    cat > ~/py/truthy.py <<'PY'for value in (0, 1, -1, 0.0, "", "0", " ", [], [0], (), {}, None):    print(repr(value).ljust(6), "->", bool(value))PYpython3 ~/py/truthy.py0      -> False1      -> True-1     -> True0.0    -> False''     -> False'0'    -> True' '    -> True[]     -> False[0]    -> True()     -> False{}     -> FalseNone   -> False

    Expected resultFalse for 0, 0.0, '', [], (), {} and None; True for everything else including '0' and [0].

    Success conditionYou can state the truth value of any object without testing it.

  4. Floats do not hold the number you wrote

    A float is a binary fraction with fixed precision, and most decimal fractions cannot be represented in it exactly. 0.1 is not really 0.1; it is the nearest binary approximation.

    That is not a Python bug and not specific to Python. It is the IEEE-754 format that essentially every language uses.

    bash Example session
    cat > ~/py/floats.py <<'PY'print(0.1 + 0.2)print(0.1 + 0.2 == 0.3)print(f"{0.1 + 0.2:.20f}")print(abs((0.1 + 0.2) - 0.3) < 1e-9)PYpython3 ~/py/floats.py0.30000000000000004False0.30000000000000004441True

    Expected result0.30000000000000004, then False, then twenty decimal places of the truth, then True.

    Success conditionYou know why an equality test on floats is unsafe and what to do instead.

  5. round() does not round the way you were taught

    round() uses banker's rounding: a value exactly halfway goes to the nearest *even* number, not always up. And a value that merely looks halfway may not be halfway at all, because of the previous step.

    Five results, and at least two of them will not be what you expect.

    bash Example session
    cat > ~/py/rounding.py <<'PY'print("round(2.5)  =", round(2.5))print("round(3.5)  =", round(3.5))print("round(-2.5) =", round(-2.5))print("round(2.675, 2) =", round(2.675, 2))print("int(2.9)    =", int(2.9))PYpython3 ~/py/rounding.pyround(2.5)  = 2round(3.5)  = 4round(-2.5) = -2round(2.675, 2) = 2.67int(2.9)    = 2

    Expected resultround(2.5) is 2, round(3.5) is 4, round(-2.5) is -2, round(2.675, 2) is 2.67, int(2.9) is 2.

    Success conditionYou can explain both surprises, and they have different causes.

  6. What the exam does with this objective

    The conversion half of 1.4 produces a small, stable set of questions:

    "What does int("3.5") do?" - raises ValueError.

    "What is bool('0')?" - True.

    "Is 0.1 + 0.2 == 0.3?" - False.

    "What is round(2.5)?" - 2.

    "What is int(-3.9)?" - -3, truncated, not -4.

    "What type is str(3.0)?" - str, and its value is '3.0'.

    The three-way distinction between int(), // and round() is the single thing most worth having straight, because a question can use any of the three on the same number and get three different answers.

    guide 9 finishes block 1 with console I/O, and contains one more trap of the same family.

    bash
    rm -f ~/py/casts.py ~/py/truthy.py ~/py/floats.py ~/py/rounding.py && ls -A ~/py

    Expected resultAn empty scratch directory.

    Success conditionYou can convert, and you know what conversion refuses to do.

Troubleshooting

Official sources