Type conversion: implicit vs explicit casting
Overview
Type conversion turns a value of one type into another. Implicit conversion happens automatically, but ONLY between numeric types. For example, adding an `int` and a `float` quietly widens the `int` to a `float`. result = 5 + 2.0 print(result) # 7.0 Explicit conversion (casting) requires you to call a constructor yourself. Across non-numeric types, Python never converts for you. - `int()` parses a number or string into an integer, returns an `int`, and raises `ValueError` on invalid formats. - `float()` parses a number or string into a floating-point number, returns a `float`, and raises `ValueError` on invalid formats. - `str()` converts a value into a string representation, returns a `str`, and generally does not raise exceptions. - `bool()` evaluates the truthiness of a value, returns a `bool`, and never raises an exception. Think of implicit conversion as Python quietly widening compatible numbers, and explicit casting as you manually translating. This translation can fail if the data is incompatible. # This will raise a TypeError: id_string = 'id_' + 5 # This will raise a ValueError: number = int('abc') One dangerous edge case involves casting strings to booleans. Non-empty strings are always truthy, even if they contain the word 'False'. is_active = bool('False') print(is_active) # True, because the string is not empty! To parse boolean strings safely from inputs like environment variables, you must explicitly check the string contents (e.g., `value == 'False'`).
APIs hand you strings (query params, env vars), so you constantly cast `'42'` to `42` — and that cast can fail, so it must be guarded. Knowing implicit conversion applies only to numbers explains why concatenating a `str` and an `int` throws instead of auto-casting.
Where used: FastAPI query/path params, parsing env vars, JSON payload handling
Why learn this
- Casting string inputs (query params, env vars) to `int`/`float` before use, and handling bad input
- Understanding why `'id_' + 5` raises a `TypeError` instead of auto-casting
Code walkthrough
total = 5 + 2.0
print(total)
age = int('30')
print(age + 1)
Focus: `5 + 2.0` auto-promotes the `int` to a `float` (implicit — note `7.0`, not `7`); the string `'30'` must be cast with `int()` before arithmetic (explicit).
Common mistakes
- Assuming Python auto-casts `str` and `int`: `'count: ' + 5` raises a `TypeError` because Python only converts implicitly between numeric types. Fix: `str(5)` or an f-string like `f'count: {5}'`.
- Unguarded `int()` on user input: `int('12abc')` raises a `ValueError`. Fix: wrap the cast in `try`/`except` (or validate first) when the input is not trusted.
Glossary
- Implicit conversion
- When the programming language automatically changes one data type into another behind the scenes. Example: `5 + 2.0`.
- concatenating
- The process of joining two strings or pieces of text together end-to-end to form a single string. Example: `'id_' + '5'`.
Recall questions
- What is the difference between implicit and explicit type conversion?
- Between which kinds of types does Python convert implicitly?
- What can go wrong with explicit casting?
- Why does `bool('False')` evaluate to `True`?
Understanding checks
What is the output of this code?
<class 'float'>
Python implicitly converts between numeric types, so it promotes the integer `5` to a `float` to match `2.0`.
What is the bug in this code?
It raises a `TypeError` because Python doesn't implicitly convert integers to strings.
You cannot concatenate a string and an integer. You must explicitly cast the integer using `str(age)` or use an f-string.
Practice tasks
Safe integer cast
The `to_int` function currently just returns the original value without modifying it. Modify its behavior to explicitly cast `value` to an integer. If the cast fails with a `ValueError`, catch it and return the `fallback` value.
Challenge
Parse a port from config
Write `parse_port(raw)` that takes a value from an env var and returns it as an `int`, defaulting to `8000` when `raw` is `None` or not a valid integer. Print calls with `'5432'`, `'abc'`, and `None`.
Continue learning
Previous: Primitive types: int, float, bool, str
Previous: Dynamic typing and type()