1.2.14 · D4Introduction to Programming (Python)

Exercises — Input with `input()` — always returns string, conversion needed

2,717 words12 min readBack to topic

One term appears again and again in the solutions below, so let's pin it down once, here on this page:

Before we start, one picture of the whole journey — every exercise is a step somewhere on this pipeline:

Figure — Input with `input()` — always returns string, conversion needed

Level 1 — Recognition

Goal: can you name the type of a value without running the code?

Recall Solution 1.1

What we're asked: the type of x, not its value. The one fact: input() always returns a str. It does not matter that the characters look like a number — the microphone recorded text. Answer: <class 'str'>

The little <class '...'> wrapper is just how Python prints a type object. The important word inside is str.

Recall Solution 1.2
  • (i) astr. Raw input() is always text: "5".
  • (ii) bint. int("5") reads the digit-text and builds the number 5.
  • (iii) cfloat. float("5") builds 5.0.
  • (iv) derror (ValueError). Here's the subtle one: int() on the string "5.0" fails, because "5.0" is not a whole-number spelling — it contains a dot. int() only accepts strings that look like plain integers. (float("5.0") would work; so would int(float("5.0")).)

Level 2 — Application

Goal: convert correctly so real operations work.

Recall Solution 2.1
  • (i) a and b are both strings, so + joins them: "3" + "4""34". Printed: 34.
  • (ii) int(a) is 3, int(b) is 4, so + now adds numbers: 3 + 47. Printed: 7.

Same +, two behaviours — decided entirely by the types of what sits either side. (See String Concatenation vs Arithmetic.)

Recall Solution 2.2
price = float(input("Price: "))    # "19.99" -> 19.99
qty   = int(input("Quantity: "))   # "3"     -> 3
print("Total:", price * qty)       # Total: 59.97

Why float for price, int for quantity? The meaning of the data chooses the converter. Money can have cents (a fractional part) → float. You can't buy 3.5 items in this model → int. Output: Total: 59.97.

Recall Solution 2.3
n = int(input("How many? "))   # "3" -> 3
print("go" * n)                # gogogo

Output: gogogo. Forgetting the conversion: "go" * "3" raises TypeError: can't multiply sequence by non-int of type 'str'. String-times-string is meaningless; string-times-int means "repeat". You must hand * an actual int.


Level 3 — Analysis

Goal: predict why code succeeds, fails, or crashes.

Recall Solution 3.1
  • (i) 42 — clean integer text.
  • (ii) 42int() strips surrounding whitespace before parsing, so leading/trailing spaces are fine.
  • (iii) ValueError — the dot makes it non-integer text; int() refuses.
  • (iv) ValueError — letters are not a number spelling.
  • (v) ValueError — the empty string has nothing to parse (this is the "user just pressed Enter" case — always possible!).
  • (vi) 3.5float() accepts decimals.
  • (vii) 1000.0float() understands scientific notation. Here 1e3 means "1 followed by 3 zeros", i.e. one thousand.

Pattern: int() is the strictest gate (whole-number spelling only). float() is more forgiving (dots, e-notation). Neither accepts letters. (See Type Conversion (Casting).)

Recall Solution 3.2

What happens: the user typed 20.5, so input() returns "20.5", and int("20.5") raises ValueError — the program crashes before print ever runs. Why: int() cannot represent the fractional .5; it does not silently round or truncate a string, it rejects it. Fix: use the converter that matches the data's meaning — decimals need float:

age = float(input("Age: "))   # "20.5" -> 20.5
print(age + 1)                # 21.5

Output: 21.5.


Level 4 — Synthesis

Goal: combine input, conversion, and guarding into a working routine.

Recall Solution 4.1
a = int(input("a: "))   # "12" -> 12
b = int(input("b: "))   # "4"  -> 4
print("sum:",  a + b)   # sum: 16
print("diff:", a - b)   # diff: 8
print("prod:", a * b)   # prod: 48
print("quot:", a // b)  # quot: 3

Why convert once at the top? We convert each input immediately into a named int, then reuse a and b everywhere. Convert-early means every later line can assume it is working with real numbers — no repeated int(...), no line accidentally left as text. Outputs: 16, 8, 48, 3 (// is integer division: 12 shared into 4 gives exactly 3).

Recall Solution 4.2
try:
    age = int(input("Age: "))
    print("Next year you are", age + 1)
except ValueError:
    print("Not a whole number!")
  • Input twenty: int("twenty") raises ValueError; control jumps to the except block → prints Not a whole number!. No crash.
  • Input 19: int("19") succeeds → 19, then prints Next year you are 20.

Why try/except here? Bad input is not a programming mistake — it is a runtime event you can expect. You catch exactly the error int() throws (ValueError, defined at the top of this page) and respond gracefully. (See Exceptions and try-except.)


Level 5 — Mastery

Goal: design robustly for every case, including the degenerate ones.

Recall Solution 5.1
while True:
    raw = input("Positive whole number: ")
    try:
        n = int(raw)
    except ValueError:
        print("That's not a whole number, try again.")
        continue
    if n <= 0:
        print("Must be positive, try again.")
        continue
    break        # only reached when n is a valid positive int
print("Thanks! You gave", n)

Trace:

  1. hiint("hi") raises ValueError → prints "not a whole number"continue → loop again.
  2. 3.5int("3.5") raises ValueError (the dot!) → same message → loop again.
  3. -4int("-4") succeeds (negative integers are valid integer text) → but n <= 0 is True → prints "Must be positive" → loop again.
  4. 7int("7") = 7, and 7 <= 0 is False, so we reach break. Final print: Thanks! You gave 7.

Why two separate guards? try/except catches malformed text (cases a, b). The if n <= 0 catches well-formed but unwanted values (case c). These are different kinds of failure and each needs its own defence. Notice case (b) is caught by the same net as (a), because int() rejects "3.5" as a string.

Recall Solution 5.2

Pressing Enter with no typing makes input() return the empty string "". Then int("") raises ValueError — there is no text to parse. This is caught by our except ValueError block → prints "not a whole number, try again" → loops. So yes, it is handled, for free, by the same guard that catches hi. This is exactly why we must think about the degenerate empty input: it is the single most common thing a distracted user does, and a robust routine survives it without special-casing.



Connections

  • Parent topic — the core rule these exercises drill.
  • Variables and Data Typesstr vs int vs float.
  • Type Conversion (Casting)int(), float() behaviour in depth.
  • String Concatenation vs Arithmetic — why + gives "34".
  • Operators in Python — overloaded + and *.
  • Exceptions and try-except — catching ValueError.
  • print() Function — displaying the results.

Level Map

L1 Recognition name the type

L2 Application convert then operate

L3 Analysis predict success or crash

L4 Synthesis input plus guard

L5 Mastery robust for every case

design an input routine from zero