Python9 min readCode verified

Variables and Types, and Why input() Broke Your Program

Four types, three kinds of division, and one fact about input() that explains most of the errors in a first Python program. Every result on this page was executed, not remembered.

input() always hands you a string#

A first program that asks a question and does arithmetic with the answer. It looks finished:

age = input("How old are you? ")
print("Next year you will be", age + 1)

What happens when you type 30? Decide before you scroll.

Traceback (most recent call last):
  File "age.py", line 2, in <module>
    print("Next year you will be", age + 1)
                                   ~~~~^~~
TypeError: can only concatenate str (not "int") to str

Read the last line literally, because it is telling you exactly what it thinks you asked for: it believes age is a str, and you asked it to join a string to the number 1. It is right. input() always returns a string — every time, no matter what the person types. Typing digits does not make it a number, and there is nothing about the prompt text that changes this.

Convert it, on the way in:

age = int(input("How old are you? "))
print("Next year you will be", age + 1)
How old are you? 30
Next year you will be 31

And int() is strict about what it will accept:

print(int("3.7"))
ValueError: invalid literal for int() with base 10: '3.7'

int() converts a string that spells a whole number. "3.7" does not, so it refuses rather than guessing whether you wanted 3 or 4. If the person might type a decimal, use float(input(...)); if you need a whole number from a decimal string, convert twice — int(float("3.7")), which gives 3.

The rule behind three different errors

Convert at the moment of input, not later. If you write age = input(...) and convert somewhere further down, then every line in between is working with a string, and each one fails differently: age + 1 raises TypeError, age * 2 silently gives you the digits twice, and age > 18 raises TypeError as well. One conversion on the input line removes all three.

The types you actually meet#

A first Python course uses four types constantly, and type() will tell you which one you are holding whenever you are unsure:

TypeWhat it holdsLiteraltype() says
intwhole numbers, no size limit42<class 'int'>
floatnumbers with a decimal point3.14<class 'float'>
strtext, in quotes"hello"<class 'str'>
boolonly True or FalseTrue<class 'bool'>

Two things about that table get examined. First, 42 and "42" are different values of different types that print identically — which is why a program can look right on screen and still be wrong. Second, bool is quietly a kind of int:

print(True + True)
print(isinstance(True, int))
2
True

True counts as 1 and False as 0. That is not a curiosity — it is why sum(results) over a list of booleans counts how many are true, and it is a favourite exam question.

Three kinds of division#

Python has more division than most languages, and the exam knows it:

print(7 / 2)
print(7 // 2)
print(7 % 2)
print(-7 // 2)
print(2 ** 10)
3.5
3
1
-4
1024
OperatorNameGives
/true divisionalways a float, even 4 / 2 is 2.0
//floor divisiona whole number, rounded down
%modulothe remainder — the tool for "is it even", "last digit", "wrap around"
**exponentpower. 2 ** 10, not 2 ^ 10

Look again at -7 // 2 giving −4. Floor division rounds toward negative infinity, not toward zero — it does not chop the decimal off, it goes down. Positive numbers hide this, because rounding down and chopping agree there. Negative numbers do not.

If you have written Java or C

7 / 2 in those languages is 3, because two whole numbers give whole-number division. In Python 3 it is 3.5. The habit transfers badly in both directions, and it is a common source of an answer that is off by exactly the fractional part.

Decimals are not exact#

print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
0.30000000000000004
False

Not a bug. A float stores numbers in binary, and one tenth has no exact binary form, exactly as one third has no exact decimal form. The sum lands a hair above 0.3, and == compares honestly and says no.

So never compare floats with ==. Either round for display — round(0.1 + 0.2, 2) gives 0.3 — or test that the difference is small enough: abs(a - b) < 1e-9. For money, work in whole cents as int.

A variable is a name, not a box#

Most explanations say a variable is a box you put a value in. That picture is fine until the day it costs you marks. Python's actual model is simpler: a variable is a name attached to a value. Assignment moves the name; it does not fill a container.

count = 5
count = count + 1
print(count)
6

Read the middle line right to left, which is the order Python does it in: work out count + 1 — that is 6 — then attach the name count to it. It is not an equation claiming that count equals count plus one, which would be false. = is an instruction, not a claim. count += 1 is shorthand for exactly the same thing.

Why the picture matters later

Once a value is a list rather than a number, two names can be attached to the same list, and changing it through one name changes what you see through the other. That surprise is the single highest-yield question in a first Python course, and it makes sense immediately if you already think of names pointing at values. It has its own guide: why changing one list changed the other.

Naming rules Python enforces, and the ones it does not#

Two of these are errors and one is silent, which is the dangerous one:

2nd = 5
SyntaxError: invalid decimal literal

A name cannot start with a digit. The message talks about a number because Python started reading 2 as one and then found a letter glued to it.

class = 5
SyntaxError: invalid syntax

class is a keyword. So are if, for, while, def, return, in, not, and, or, None, True and False. You do not need to memorise the list — a decent editor colours them, and the error arrives instantly.

Score = 1
score = 2
print(Score, score)
1 2

This is the silent one. Python is case sensitive, so Score and score are two unrelated variables. No error, no warning — just a program that updates one name and reads the other. The convention that prevents it is snake_case: lowercase words joined by underscores, final_score, every time.

Printing things next to each other#

Two ways to put a label in front of a number, and they are not the same:

n = 5
print("n =", n)
print("n = " + str(n))
n = 5
n = 5

Identical output, different mechanisms. The comma passes two separate arguments to print, which converts each one and joins them with a space for you — it never raises a TypeError, whatever the types. The + is string concatenation, which demands that both sides already be strings, which is why str(n) is there and why dropping it produces the same TypeError this guide opened with.

Two options change the joining:

print("a", "b", sep="-")
print("x", end="")
print("y")
a-b
xy

sep replaces the space between arguments; end replaces the newline print normally adds at the end, which is how you build one line of output from several print calls inside a loop.

Where these go wrong#

  • Doing arithmetic on input() without converting. The single most common first-course bug. int(input(...)) or float(input(...)), on the input line.
  • Using / where a count is wanted. len(xs) / 2 is a float, so it cannot index a list. len(xs) // 2 can.
  • Comparing floats with ==. It compiles, it runs, and it says False for values that print identically.
  • Comparing numbers that are still strings. "10" < "9" is True — that is alphabetical order, not numeric. 10 < 9 is False. No error either way.
  • A capitalisation typo in a variable name. Silent, and it looks like the assignment did not happen. snake_case everywhere makes it rare.
  • Expecting -7 // 2 to be −3. Floor division rounds down, not toward zero.
  • Assuming 4 / 2 is an int. It is 2.0. Anything printed from it carries the .0.

Test yourself in the free Kestrel Exams app

Topic-selectable practice — offline, no ads, no account.

Practice this topic →

Frequently asked questions#

Why does input() + 1 give a TypeError?

Because input() always returns a string, even when the person types digits. "30" + 1 asks Python to join text to a number, which it refuses to guess at. Convert on the input line: age = int(input("How old are you? ")). Use float() instead if a decimal is possible.

What is the difference between / and // in Python?

/ is true division and always produces a float, so 7 / 2 is 3.5 and even 4 / 2 is 2.0. // is floor division and produces a whole number rounded down, so 7 // 2 is 3. Rounding down is not the same as chopping the decimal off: -7 // 2 is −4, not −3.

Why does int("3.7") fail?

int() converts a string that spells a whole number, and "3.7" does not, so it raises ValueError rather than guessing between 3 and 4. Use float("3.7") to get 3.7, or int(float("3.7")) to get 3.

Is Python case sensitive for variable names?

Yes. Score and score are two completely separate variables, and using the wrong one produces no error at all — just a program that stores a value under one name and reads another. The snake_case convention makes this mistake rare.

Why is 0.1 + 0.2 not equal to 0.3 in Python?

Floats are stored in binary, and one tenth has no exact binary representation, just as one third has no exact decimal one. The sum comes out as 0.30000000000000004. Never compare floats with ==; round for display, or test that abs(a - b) is smaller than a small tolerance.

Is True really a number in Python?

Yes. bool is a subclass of int, with True worth 1 and False worth 0. True + True is 2. This is why sum() over a list of booleans counts how many are true.

Suggest a change

Something here not clear? A topic you wish we covered? Tell us. We read every message, and a request is the fastest way to get a guide written — several of these exist because somebody asked.