Technology  /  Python

🐍 Python 78 guides · updated 2026

From first variable to OOP, generators, and real projects β€” the language that runs everything from data pipelines to AI agents, taught the practical way.

Type Conversion in Python: Implicit, Explicit, and the Pitfalls Between Them

Python handles type conversion in two distinct ways: automatically in situations where the conversion is safe and reversible, and by refusing β€” loudly, with a TypeError β€” in situations where guessing would be dangerous. Understanding which situations fall into which category saves you from both cryptic errors and unexpected results.


Implicit Type Conversion

Python promotes types automatically when combining numeric types, because no information is lost going in that direction:

# int + float β†’ float
result = 10 + 3.5
print(result) # 13.5
print(type(result)) # <class 'float'>
# int + complex β†’ complex
z = 5 + 2j
print(type(z)) # <class 'complex'>
# bool behaves as int in arithmetic
print(True + 1) # 2 (True == 1)
print(False + 10) # 10 (False == 0)
print(sum([True, True, False, True])) # 3 β€” counts True values

The promotion hierarchy is: bool β†’ int β†’ float β†’ complex. Python will always promote to the more general type to avoid data loss.

What Python will not do implicitly: convert a string to a number, or convert a number to a string. Those conversions require explicit intent because they can fail or lose information:

# This raises TypeError β€” Python refuses to guess
total = "10" + 5 # TypeError: can only concatenate str (not "int") to str

Explicit Type Conversion (Casting)

When you need to change types, Python provides built-in functions for each conversion.

int()

Converts to integer. Accepts strings of digits, floats (truncates, does not round), and booleans:

print(int("42")) # 42
print(int(9.99)) # 9 β€” truncates, not rounds
print(int(9.01)) # 9 β€” same direction regardless
print(int(True)) # 1
print(int(False)) # 0
print(int("0xFF", 16)) # 255 β€” specify base for non-decimal strings
# These raise ValueError
int("3.14") # can't convert a float string directly
int("hello") # obviously can't convert
int("") # empty string fails too

The truncation behaviour catches people out. If you want rounding, use round() first:

value = 9.7
print(int(value)) # 9 β€” truncated
print(round(value)) # 10 β€” rounded
print(int(round(value))) # 10 β€” rounded then converted

float()

Converts to floating-point. More permissive than int() β€” it handles decimal strings:

print(float("3.14")) # 3.14
print(float("42")) # 42.0
print(float(True)) # 1.0
print(float("1e3")) # 1000.0 β€” scientific notation works
# These raise ValueError
float("three point one four")
float("")

str()

Converts anything to its string representation. Almost never fails:

print(str(42)) # "42"
print(str(3.14)) # "3.14"
print(str(True)) # "True"
print(str(None)) # "None"
print(str([1, 2, 3])) # "[1, 2, 3]"

The most common use is building strings for output when you can’t use an f-string:

log_parts = ["Error", str(error_code), "at line", str(line_number)]
message = " ".join(log_parts)

bool()

Converts to True or False based on Python’s truthiness rules:

# Falsy values β€” convert to False
print(bool(0)) # False
print(bool(0.0)) # False
print(bool("")) # False
print(bool([])) # False
print(bool({})) # False
print(bool(None)) # False
# Everything else is True
print(bool(1)) # True
print(bool(-1)) # True (non-zero)
print(bool("hello")) # True
print(bool([0])) # True (non-empty list, even with falsy content)

This is why Python conditional checks like if items: work β€” if items: is equivalent to if bool(items):, which is False when items is an empty list.


Converting Between Collections

You can convert between list, tuple, and set freely. Converting to a set removes duplicates and loses order:

original = [3, 1, 4, 1, 5, 9, 2, 6, 5]
as_tuple = tuple(original) # (3, 1, 4, 1, 5, 9, 2, 6, 5)
as_set = set(original) # {1, 2, 3, 4, 5, 6, 9} β€” unordered, unique
# Common pattern: deduplicate while preserving order
deduped = list(dict.fromkeys(original))
print(deduped) # [3, 1, 4, 5, 9, 2, 6]

Conversions That Lose Data

Some conversions are lossy β€” you can’t go back to the original value:

# Float to int loses decimal precision
x = 3.99
print(int(x)) # 3 β€” the .99 is gone
# Float arithmetic can lose precision
total = 0.1 + 0.2
print(total) # 0.30000000000000004
print(str(total)) # "0.30000000000000004"
# Converting a set loses ordering
items = [3, 1, 2, 1, 3]
unique = list(set(items)) # could be [1, 2, 3] or any order

When precision matters β€” financial calculations, scientific data β€” avoid float arithmetic and use the decimal module instead:

from decimal import Decimal
price = Decimal("10.99")
tax = Decimal("0.08")
total = price * (1 + tax)
print(total) # 11.8692 β€” exact decimal arithmetic

Safe Conversion Patterns

Wrap conversions that can fail in try/except:

def safe_int(value, default=None):
"""Convert value to int, returning default on failure."""
try:
return int(value)
except (ValueError, TypeError):
return default
print(safe_int("42")) # 42
print(safe_int("hello")) # None
print(safe_int("3.7")) # None β€” int() won't accept float strings
print(safe_int("3.7", 0)) # 0

For user input especially, always anticipate conversion failures and handle them gracefully rather than letting the program crash.