Chapter 5 of 24 · Python for Beginners — Complete Free Tutorial
Numbers, Operators and Type Conversion
Arithmetic looks familiar until the first time / returns a decimal where you expected a whole number. The Python for Beginners series now covers Python’s numeric types, its full operator set, the precedence rules that decide evaluation order, the standard-library math module, and the conversions — successful and otherwise — that connect numbers to text.
Integers, floats and everyday arithmetic
Python has two numeric built-ins you will use constantly. int is unlimited-precision, so 2 ** 1000 is exact; float is a 64-bit binary fraction, which is fast but never quite exact in decimal. All the usual operators work on both:
print(7 + 3)
print(7 - 3)
print(7 * 3)
print(7 / 3)
print(7 // 3)
print(-7 // 3)
print(7 % 3)
print(2 ** 10)
Expected output:
10
4
21
2.3333333333333335
2
-3
1
1024
Three results deserve a name. / is true division and always produces a float, even when the answer is whole (6 / 3 is 2.0). // is floor division: it discards the fractional part rounding down, not towards zero — that is why -7 // 3 is -3 and not -2. % is the modulo, and for negatives it follows the same rule, so -7 % 3 is 2. Together, // and % split a number into quotient and remainder: divmod(7, 3) hands back (2, 1).
Floats are binary, so some decimal values do not survive the trip:
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
Expected output:
0.30000000000000004
False
Every language with 64-bit floats has this quirk; the habit to form early is formatting for display (f"{value:.2f}") and comparing with a tolerance rather than with ==.
Exponent, precedence and augmented assignment
The exponent operator ** binds tighter than multiplication, and it associates to the right, so powers stack upwards before anything else is considered. Unary minus binds looser still, which surprises almost everyone once:
print(2 + 3 * 4)
print((2 + 3) * 4)
print(2 ** 3 ** 2)
print(-2 ** 2)
Expected output:
14
20
512
-4
2 ** 3 ** 2 is 2 ** 9, not 8 ** 2, and -2 ** 2 is -4 because it means -(2 ** 2) — write (-2) ** 2 if you want 4. The full precedence ladder, from tightest to loosest, is: parentheses, exponent, unary +/-, * / // %, then + and -, then comparisons, then not, then and, then or. When in doubt, add the parentheses: they cost one keystroke and they document the intent.
Compound operators fold the operation into the assignment:
total = 10
total += 5
total *= 2
total -= 4
print(total)
Expected output:
26
total //= 3, total **= 2 and total %= 7 exist for the same operators. In a loop counter or a running sum, the augmented form is the idiomatic choice.
Comparison operators and chaining
Six comparison operators — ==, !=, <, >, <=, >= — and one assignment operator that is easy to mistake for one of them: = assigns, == compares. Unlike JavaScript, Python never coerces across types, so comparing a number with a string is not a lie waiting to happen — it is simply False:
print(5 == "5")
print(5 != "5")
score = 78
print(0 <= score <= 100)
print(90 <= score < 100)
Expected output:
False
True
True
False
The last two lines are chained comparisons: 0 <= score <= 100 means exactly 0 <= score and score <= 100, with score evaluated once. They read like the maths they represent and are the standard way to express ranges — you will write them inside if statements in the next chapter. Strings compare by their Unicode code points, which is why "a" < "b" is true and why "Z" < "a" is also true.
The math module
The four arithmetic operators are built in; everything else lives in the standard library. import math brings in constants and functions that would only clutter the global namespace:
import math
print(math.pi)
print(math.sqrt(16))
print(math.ceil(2.1))
print(math.floor(2.9))
print(round(3.14159, 2), round(2.5), abs(-3))
Expected output:
3.141592653589793
4.0
3
2
3.14 2 3
Notice that sqrt returns a float even for a whole answer, while ceil and floor return ints. round() and abs() needed no import — they are builtins — and round(2.5) giving 2 is not a bug: ties round to the nearest even digit, a policy that stops large batches of numbers drifting upwards. math also holds math.gcd(), math.isclose() and math.comb(); the full list is worth a skim in the official documentation.
Converting between types
Mixing an int and a float promotes silently — 2 + 2.5 is 4.5. Text is different: conversion is always explicit, and always through one of four constructors:
print(int("42"))
print(int(3.9))
print(float("3.5"))
print(str(42) + " items")
print(bool(""))
print(bool("hi"))
Expected output:
42
3
3.5
42 items
False
True
int(3.9) truncates towards zero rather than rounding — that is deliberate, so int() never silently changes a magnitude. Converting to text is what str() is for; "5" + 5 raises TypeError: can only concatenate str (not "int") to str instead of quietly producing nonsense as JavaScript does with "5" + 5. And bool() answers the question “is this value non-empty?”, which is the whole of chapter 6 in one function.
Text to number is where beginners meet their first ValueError. Only a correctly formed decimal string converts — int(" 42 ") works because surrounding spaces are ignored, but a decimal point is not:
total = int("3.9")
print(total)
Expected output:
Traceback (most recent call last):
File "totals.py", line 1, in <module>
total = int("3.9")
ValueError: invalid literal for int() with base 10: '3.9'
The message is worth reading closely: int() received something that is not an integer literal, and it will not round 3.9 for you. To convert, decide first whether you want int(float("3.9")) (two steps, gives 3) or round(float("3.9")). The float constructor fails the same way on non-numbers — ValueError: could not convert string to float: 'abc' — and every conversion you will meet in later chapters, int() from a JSON field or float() from user input, follows this pattern. Chapter 12 shows how to catch the exception instead of crashing.
Common mistakes
- Expecting
/to return a whole number — it never does; use//when you want an integer quotient. - Truncating negative numbers the C way —
-7 // 3is-3, because floor division rounds down; usemath.trunc()if you need-2. - Comparing floats with
==—0.1 + 0.2 == 0.3is false; format for display and compare with a tolerance. - Writing
int("3.9")and expecting rounding — it raisesValueError; convert to float first, then round. - Forgetting operator precedence —
2 + 3 * 4is 14; if you had to stop and think, add parentheses for the reader anyway.
Practice checklist
- Compute then predict:
17 // 5,17 % 5,-17 // 5,17 / 5and2 ** 0.5. - Write a statement that turns
minutesinto hours and remaining minutes using//and%, and test it with 145. - Evaluate
2 * 3 + 4 ** 2 / 2by hand from the precedence ladder, then check it withpython3. - Print
math.pito three decimals with an f-string and provemath.ceil()andmath.floor()disagree on2.5. - Trigger the
int("3.9")error yourself, read every word of the traceback, and fix it the two ways described above.
What's next?
Numbers, operators and conversions are in place; now the program needs to choose between paths — Control Flow and Conditionals is next.
Frequently Asked Questions
Python is a general-purpose language first released in 1991, designed around one idea: code is read far more often than it is written. English keywords and indentation instead of braces make it readable, the standard library covers files, JSON, dates and testing, and pip adds thousands more packages. The same language handles scripts, web APIs, data work and machine learning.
None at all. Python is widely considered the friendliest first language: no declaration keywords, no braces, no build step, and error messages that name the problem. This series begins at your first print() call. If you already read JavaScript or TypeScript you will adjust quickly, but no previous language is assumed anywhere in these 24 chapters.
Python 3 only, any release from 3.12 onwards. Python 2 reached end of life in 2021 and its print "hi" statements and xrange() no longer run. One historical quirk remains: installers ship the interpreter as python3 on macOS and Linux, while Windows usually offers python or the py launcher, and every command in this series works with that one-word swap.
More than you might expect. Everyday automation such as renaming files, cleaning spreadsheets or scraping pages; web backends with Django, Flask or FastAPI; data analysis and machine learning with pandas, NumPy and PyTorch; DevOps tooling, desktop apps and games. Python is also the classic glue language, calling C, Rust or Fortran libraries from short readable scripts.
Pure Python can run 10 to 100 times slower than C, yet that rarely blocks you: heavy numeric work lives in C extensions such as NumPy, which Python coordinates. Dynamic typing does push errors to runtime, surfacing as a TypeError on the line that finally uses the bad value. Type hints checked by mypy move those mistakes back into your editor.
Only the interpreter. Install CPython from python.org, version 3.12 or newer, confirm it with python3 --version, and open a plain text editor; VS Code with the Python extension is the recommendation here. The early chapters use no third-party packages, so there is nothing else to set up until virtual environments and pip arrive.
A dict is a real runtime mapping: keys may be any hashable value rather than only strings, insertion order has been guaranteed since Python 3.7, and a missing key raises KeyError unless you ask with get(). JavaScript objects coerce every key to a string and carry a prototype chain. A TypeScript interface is erased at compile time and describes shape only; TypedDict is Python's checked equivalent.
Reach for a list when items will be added, removed or reordered: it is ordered, mutable and rich with methods. Pick a tuple for fixed records and function returns, because it is immutable and hashable, so it can be a dictionary key. Choose a set for unique values and fast membership checks; it has no order and de-duplicates on creation.
Yes, gradually. Annotate public function signatures first; the interpreter ignores hints at runtime, so a checker such as mypy is what gives them teeth. Add tests the same way: pytest collects any test_*.py file and plain assert statements, and a suite that finishes in a tenth of a second is one you will run after every change. Both habits cost little now and much more later.
JavaScript and TypeScript keep the browser, so anything rendered to the user stays theirs. Python takes the server: Django for full-featured applications, Flask for small ones, FastAPI for typed async APIs where your annotations become automatic documentation. Your TypeScript habits transfer directly, and asyncio mirrors the event loop you already know, just with different keywords.