Type conversion in Python changes a value from one data type to another, either implicitly, when Python widens a number during arithmetic, or explicitly, when we call a constructor such as int(), float() or str(), which is also called type casting. Python never converts between unrelated types such as numbers and strings by itself, so mixing them raises a TypeError.
total = 11 + 1.1 # 12.1, int widened to float (implicit)
count = int("42") # 42, str converted to int (explicit)
label = "Total: " + str(total) # 'Total: 12.1'
This tutorial explains implicit conversion and the TypeError for incompatible types, explicit casting, a reference table of conversion functions with their return values, and the data loss and parsing errors that come with casting, with output from Python 3.14.
1. Type Conversion
Every value in Python has a type, and the type decides which operations are allowed. Converting a value creates a new object of the target type and leaves the original unchanged. Python supports two kinds of conversion.
- Implicit conversion happens inside an expression, without any function call.
- Explicit conversion happens when we call a type constructor or a conversion function.
2. Implicit Type Conversion
Python converts implicitly only between numeric types, and only toward the wider type in the order bool, int, float and complex. The value is kept, except for integers above 2**53, which lose precision as floats.
2.1. Example: Convert int to float
We add an int and a float. Python widens the integer to a float before the addition, so the result is a float.
int_val = 11
flo_val = 1.1
flo_sum = int_val + flo_val
print("datatype of flo_sum:", type(flo_sum))
print("value of flo_sum:", flo_sum)
datatype of flo_sum: <class 'float'>
value of flo_sum: 12.1
The same rule covers other numeric pairs. True division also returns a float, even for two integers.
as_int = True + 1 # 2, bool is a subclass of int
as_complex = 1 + 2j # (1+2j)
division = 3 / 2 # 1.5, a float
floor_float = 7 // 2.0 # 3.0, a float because one operand is float
2.2. TypeError: Incompatible Data Types
Numbers and strings are not compatible, and Python does not guess which conversion we want. Adding an integer to a string raises a TypeError.
int_val = 11
str_val = "1.1"
try:
val_sum = int_val + str_val
except TypeError as e:
message = str(e) # "unsupported operand type(s) for +: 'int' and 'str'"
With the string on the left side, the message changes to can only concatenate str (not “int”) to str. Both errors are fixed with an explicit conversion.
3. Explicit Type Conversion
Explicit conversion calls a built-in function that builds a new value of the target type. The direction we choose decides the result.
3.1. Example: Adding an Integer to a String
Converting the number to a string joins the two values as text. Converting the string to a number adds them.
int_val = 11
str_val = "1.1"
as_text = str(int_val) + str_val # '111.1'
as_number = int_val + float(str_val) # 12.1
For building text, an f-string converts values on its own and reads better than str() with +, as in f”{int_val} items”.
3.2. Converting Between Collections
The collection constructors accept any iterable. Converting to a set removes duplicates, and converting a dictionary to a list keeps only its keys.
letters = list("abca") # ['a', 'b', 'c', 'a']
unique = sorted(set(letters)) # ['a', 'b', 'c']
frozen = tuple([1, 2, 3]) # (1, 2, 3)
pairs = dict([("a", 1), ("b", 2)]) # {'a': 1, 'b': 2}
keys = list({"x": 1, "y": 2}) # ['x', 'y']
4. Type Conversion Functions
These built-in functions do the explicit conversions. A value of the wrong type raises TypeError, while a value of the right type with bad content, such as int(“abc”), raises ValueError.
| Function | Converts | Return value | Example |
|---|---|---|---|
| int(x, base=10) | Number or numeric string to integer | int | int(“ff”, 16) returns 255 |
| float(x) | Number or numeric string to float | float | float(“1e3”) returns 1000.0 |
| complex(real, imag) | Numbers or a string such as “1+2j” | complex | complex(“1+2j”) returns (1+2j) |
| str(x) | Any object to its text form | str | str(3.5) returns ‘3.5’ |
| bool(x) | Any object to its truth value | bool | bool(“”) returns False |
| list(it), tuple(it), set(it) | Iterable to a collection | list, tuple, set | tuple(“ab”) returns (‘a’, ‘b’) |
| dict(pairs) | Key-value pairs to a dictionary | dict | dict([(“a”, 1)]) returns {‘a’: 1} |
| chr(i), ord(c) | Code point to character and back | str, int | chr(65) returns ‘A’, ord(“A”) returns 65 |
| hex(i), oct(i), bin(i) | Integer to a prefixed string in base 16, 8 or 2 | str | hex(255) returns ‘0xff’ |
| bytes.decode(), str.encode() | Bytes to text and back | str, bytes | b”hi”.decode() returns ‘hi’ |
The chr() and ord() functions work with any Unicode code point, not only ASCII. The Python ascii() tutorial shows how code points appear in escaped text.
5. Data Loss and Common Conversion Errors
Explicit conversion can drop data, as when a float is truncated to an integer. Some other conversions surprise beginners as well.
truncated = int(3.99) # 3, the fraction is dropped
toward_zero = int(-3.99) # -3, truncation goes toward zero
rounded = round(3.99) # 4
big = 2**53 + 1 + 0.0 # 9007199254740992.0, precision lost
true_text = bool("False") # True, any non-empty string is truthy
text_of_bytes = str(b"hi") # "b'hi'", use decode() instead
Strings must contain a value in the exact format the target type expects. A decimal point in an int() call or a thousands separator in a float() call raises ValueError.
>>> int("12.5")
ValueError: invalid literal for int() with base 10: '12.5'
>>> float("1,000")
ValueError: could not convert string to float: '1,000'
>>> int(None)
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
We convert “12.5” with int(float(“12.5”)) and remove separators with s.replace(“,”, “”) before parsing. The Python int tutorial covers bases and the 4300-digit limit.
6. Real-World Example: Parsing a Form Submission
Web forms and CSV files deliver every field as a string. A small function converts each field to its target type and collects the errors instead of failing on the first one.
form = {"qty": "3", "price": "19.99", "gift": "on", "coupon": ""}
def parse_order(data):
errors = []
try:
qty = int(data["qty"])
except ValueError:
qty, errors = 0, errors + ["qty must be a whole number"]
try:
price = float(data["price"])
except ValueError:
price, errors = 0.0, errors + ["price must be a number"]
gift = data.get("gift") == "on" # checkbox to bool
coupon = data.get("coupon") or None # empty string to None
return {"qty": qty, "price": price, "gift": gift, "coupon": coupon}, errors
order, problems = parse_order(form)
# order = {'qty': 3, 'price': 19.99, 'gift': True, 'coupon': None}, problems = []
Converting the checkbox with bool(data[“gift”]) would be wrong, because the string “off” is also truthy. Comparing with the expected value is the safe conversion.
7. Type Conversion FAQs
The most frequent questions about casting cover naming, validation and strings.
7.1. What is the difference between type conversion and type casting?
Python uses both terms for the same thing. Some tutorials reserve type casting for explicit conversion with functions such as int(), and type conversion for both kinds.
7.2. How do we check whether a string can be converted to a number?
The reliable way is to try the conversion and catch ValueError. The str.isdigit() method rejects valid inputs such as “-5” and “1.5”.
7.3. Does Python convert a string to a number on its own?
No. Python is strongly typed, so “5” * 2 repeats the string as ’55’ and “5” + 2 raises TypeError. Only numeric types are widened.
8. Conclusion
Automatic widening happens only for numbers, from bool up to complex. Everything else needs an explicit call to int(), float(), str() or a collection constructor, and those calls can lose data or raise ValueError and TypeError, so input from users and files belongs inside a try block.
9. References
Happy Learning !!