Python Numbers: int, float, and complex Explained
Python has three built-in numeric types: int for whole numbers, float for decimal numbers, and complex for numbers with a real and imaginary part. They work together in arithmetic, but they do not behave the same way, so it helps to know when Python keeps exact values and when it switches to approximation. This article explains how each type works, how Python chooses results, and the mistakes beginners make with numeric code.
Difficulty: Beginner
Helpful to know first: basic Python variables, assignment with =, and simple arithmetic operators like + and *.
How Python Stores Whole Numbers, Decimals, and Complex Values
Python chooses a numeric type based on the value you write and the kind of math you need. A whole number such as 42 is an int. A number with a decimal point such as 42.0 is a float. A complex number uses the form a + bj, where a is the real part and b is the imaginary part.
Python keeps int values exact. It stores float values in binary floating-point format, which is fast and useful for most decimal calculations but can create tiny rounding surprises. complex values store two floats: one for the real part and one for the imaginary part.
print(type(7)) # Output: <class 'int'>
print(type(7.0)) # Output: <class 'float'>
print(type(7 + 3j)) # Output: <class 'complex'>This shows the three numeric types directly. The value you write determines the type, and the type affects later operations.
Using int for Exact Whole-Number Math
int is the type to use when you need exact counting: items in a cart, loop counters, ages, page numbers, or any value that should never contain a fraction. Python integers can grow as large as memory allows, so you do not need to pick a fixed size such as 32-bit or 64-bit for ordinary Python code.
Integer arithmetic stays exact. Division is the main exception: the / operator always returns a float, even when both sides are whole numbers. If you want the quotient without the remainder and still want an integer result, use //.
print(10 + 3) # Output: 13
print(10 - 3) # Output: 7
print(10 * 3) # Output: 30
print(10 / 3) # Output: 3.3333333333333335
print(10 // 3) # Output: 3
print(10 % 3) # Output: 1These operators are the core of numeric code in Python. The division operators are especially important because they do not all return the same type.
Using float for Decimal Values and Approximate Calculations
float is the type to use for measurements, averages, scientific values, and other numbers that can have fractional parts. It supports arithmetic in the same way int does, but a float is an approximation of a real number, not a perfect decimal representation for every value.
The most important beginner surprise is that some decimal values cannot be represented exactly in binary. That is why simple-looking expressions can produce results with a long tail of digits.
print(0.1 + 0.2) # Output: 0.30000000000000004
print(round(0.1 + 0.2, 1)) # Output: 0.3The first line shows the representation issue. The second line shows one common way to present a rounded result, but rounding does not change how the number is stored; it only changes the value you get back from round.
Why float comparisons need care
Because floats can contain tiny representation errors, comparing them with == can fail even when the values look the same on screen. A safer pattern is to compare whether the difference is small enough for your use case.
a = 0.1 + 0.2
b = 0.3
print(a == b) # Output: False
print(abs(a - b) < 1e-9) # Output: TrueThis difference matters in finance, measurement, and any code that tests exact decimal equality. The closer your work is to real-world quantities, the more likely you are to need a tolerance.
Using complex for Two-Part Numbers
complex numbers are built into Python and are written with the imaginary unit j, not i. Python uses them for math that has a real and imaginary component, such as signal processing, electrical engineering, and some scientific formulas.
You can access the real and imaginary parts with .real and .imag. Like floats, complex numbers are immutable: operations create new values instead of changing the original number.
z = 2 + 3j
print(z) # Output: (2+3j)
print(z.real) # Output: 2.0
print(z.imag) # Output: 3.0
print(z * 2) # Output: (4+6j)Notice that the real and imaginary parts are returned as floats. That is normal, even if you start with whole numbers.
How Python Chooses a Result Type in Mixed Math
When you mix numeric types, Python follows promotion rules. The important rule is simple: if one side is a float, the result is usually a float; if one side is complex, the result is complex. Integers are promoted to fit the wider type.
print(5 + 2.5) # Output: 7.5
print(5 + 2j) # Output: (5+2j)
print(5 / 2) # Output: 2.5
print(type(5 / 2)) # Output: <class 'float'>This is why a calculation that starts with integers can end with a float. Once division happens, later arithmetic may stay in float form unless you convert back to int carefully.
Converting between numeric types
Python gives you built-in conversion functions for explicit changes. Use int() to drop the fractional part toward zero, float() to make a decimal number, and complex() to build a complex value.
print(int(3.9)) # Output: 3
print(int(-3.9)) # Output: -3
print(float(4)) # Output: 4.0
print(complex(4)) # Output: (4+0j)This conversion behavior matters because int() does not round; it truncates toward zero. That is a frequent source of off-by-one mistakes when people expect rounding instead of dropping the fraction.
How Numbers Work in Loops, Ranges, and Counting
Numbers show up constantly in loops. The range() function uses integers and is one of the most common places where beginners need to reason about number types and off-by-one behavior.
for index in range(3):
print(index)
# Output:
# 0
# 1
# 2range(3) produces the integers 0, 1, and 2. The ending value is excluded, so the loop runs three times, not four. This matters any time you use a number to count items, pages, or indexes.
A lot of beginner bugs are not about the arithmetic itself. They come from forgetting whether a number is a count, an index, or a result of division.
How Number Formatting Differs from Number Storage
Printing a number and storing a number are not the same thing. Formatting changes how a number looks; it does not change the underlying value unless you assign the formatted result back as a different type. This is especially important with floats, where the stored value may contain more precision than you want to display.
value = 12.34567
print(round(value, 2)) # Output: 12.35
print(value) # Output: 12.34567The rounded result is a new value for that expression. The original variable still holds the original float.
How Python Numbers Differ from Strings That Look Like Numbers
A string such as "42" is not a number, even though it contains digits. Python does not automatically convert strings into numeric types in arithmetic. You must convert the string first if you want numeric behavior.
age_text = "21"
age = int(age_text)
print(age + 1) # Output: 22Without the conversion, Python would treat the value as text, not as a quantity. That difference matters everywhere you read user input or data from files.
Predict the Output
Read each snippet carefully and decide what Python prints before you open the answer.
Integer division and float division
print(9 // 2)
print(9 / 2)What does this print?
Show answer
// performs floor division and returns the integer part of the quotient, so the first line prints 4. The / operator always returns a float, so the second line prints 4.5.
# Output:
# 4
# 4.5Mixing int and float
total = 5
total += 2.0
print(type(total))
print(total)What happens?
Show answer
total starts as an int, but adding 2.0 promotes the result to float. The first line prints the float type, and the second line prints the decimal value.
# Output:
# <class 'float'>
# 7.0Common Mistakes with Python Numbers
Using / when you want an integer result
Beginners often expect / to keep a value whole when both inputs are whole numbers. In Python, that is not how it works.
Problem: This code produces a float, which can break code that expects an integer index or count.
items = 10
pages = items / 3
print(pages)Fix: Use // for floor division when you want an integer quotient.
items = 10
pages = items // 3
print(pages)The corrected version works because // returns the whole-number part of the division.
Comparing floats with ==
Float values can look equal when printed but still differ slightly in memory.
Problem: This comparison can fail because the two expressions may not produce exactly the same stored value.
result = 0.1 + 0.2
print(result == 0.3)Fix: Compare with a small tolerance using abs().
result = 0.1 + 0.2
print(abs(result - 0.3) < 1e-9)The fixed version works because it checks for a small acceptable difference instead of exact binary equality.
Using int() when you really need rounding
int() removes the fractional part rather than rounding to the nearest whole number.
Problem: This code truncates 9.9 to 9, which may be the wrong result if you wanted the nearest integer.
score = 9.9
print(int(score))Fix: Use round() when you want normal rounding.
score = 9.9
print(round(score))The corrected version works because round() chooses the nearest integer instead of dropping the fraction.
Find the Bug
Here is a small program that looks reasonable but gives the wrong result for one common beginner task. Find the bug before opening the answer.
def average(numbers = [1, 2, 3]):
return sum(numbers) // len(numbers)
print(average())What is wrong with this code?
Show answer
The bug is //. Floor division throws away the decimal part, so the average of 1, 2, and 3 becomes 2 by luck, but many other inputs would be wrong. The function should use normal division so the result can be a float when needed.
Fixed code:
def average(numbers = [1, 2, 3]):
return sum(numbers) / len(numbers)
print(average())The fixed version works because average values are often not whole numbers, so / preserves the fractional part.
When to Use int, float, and complex
Choose the type that matches the kind of number you really have. The wrong choice usually causes bugs later, not at the point where you first write the value.
| Use this type | When it fits | Example |
|---|---|---|
| int | Counting whole things, indexes, lengths, and exact whole-number math | 5, items[2] |
| float | Measurements, averages, percentages, and decimal approximations | 3.14, temperature / 10 |
| complex | Mathematics with real and imaginary parts | 2 + 3j |
If you are writing ordinary business logic, int and float cover most needs. complex is specialized and appears much less often in beginner projects.
Interview Questions About Python Numbers
Why does / return a float even for two integers?
Because Python follows numeric semantics where true division always produces the mathematically correct quotient as a float when needed. If you want integer-style division, use //.
Why can two equal-looking floats compare as not equal?
Because floats are stored in binary approximation form. Some decimal values cannot be represented exactly, so tiny differences can appear after arithmetic.
When would you use complex numbers in real code?
Mainly in scientific and engineering code, especially signal processing, control systems, and formulas that naturally use an imaginary component. Most application code never needs them.
Try It Yourself
Write a short program that calculates the cost per item from a total price and item count.
- Set total_price to 19.95.
- Set item_count to 4.
- Compute the price per item.
- Print the result rounded to 2 decimal places.
Expected output:
4.99Hint: Use normal division to get a decimal result, then pass the value to round(..., 2).
Show solution
total_price = 19.95
item_count = 4
price_per_item = total_price / item_count
print(round(price_per_item, 2)) # Output: 4.99Summary
- int stores exact whole numbers and is the best choice for counting and indexing.
- float stores approximate decimal values and can show tiny rounding differences.
- complex stores a real and imaginary part and uses j for the imaginary unit.
- / returns a float, while // returns floor division.
- Convert numeric types explicitly with int(), float(), and complex() when needed.
- For a next topic, learn how Python handles strings and how text differs from numbers.