Python - Type Conversion (int, float, str, bool)

Type conversion is the process of transforming data from one type to another. In Python, you'll encounter this constantly: parsing user input from strings to numbers, converting API responses,...

Key Insights

  • Python’s type conversion functions (int(), float(), str(), bool()) truncate rather than round, reject invalid formats, and follow specific truthy/falsy rules—understanding these behaviors prevents subtle bugs.
  • Always wrap type conversions in try/except blocks when dealing with external data; a single malformed input can crash your entire application.
  • Boolean conversion follows Python’s “truthiness” concept where empty collections, zero values, and None evaluate to False—this pattern is fundamental to writing idiomatic Python code.

Introduction to Type Conversion

Type conversion is the process of transforming data from one type to another. In Python, you’ll encounter this constantly: parsing user input from strings to numbers, converting API responses, cleaning data for analysis, or simply concatenating a number with a string for display.

Python handles type conversion in two ways. Implicit conversion (coercion) happens automatically when Python determines it’s safe. Add an integer to a float, and Python silently promotes the integer to a float. Explicit conversion (casting) requires you to call a conversion function directly—int(), float(), str(), or bool().

# Implicit conversion - Python handles this automatically
result = 5 + 3.2  # int + float → float (8.2)

# Explicit conversion - You must specify the conversion
user_age = int("25")  # string → int

The distinction matters because implicit conversion is limited to “safe” operations where no data loss occurs. Everything else requires explicit conversion, and that’s where understanding the rules becomes critical.

Converting to Integers with int()

The int() function converts values to integers, but its behavior varies significantly based on the input type.

From Floats: Truncation, Not Rounding

This trips up developers constantly. int() truncates toward zero—it doesn’t round.

int(3.9)   # Returns 3, not 4
int(3.1)   # Returns 3
int(-3.9)  # Returns -3, not -4 (truncates toward zero)
int(-3.1)  # Returns -3

If you need rounding, use round() first:

round(3.9)       # Returns 4
int(round(3.9))  # Returns 4

From Strings: Strict Parsing

int() parses strings containing valid integer representations. It’s strict—no decimals, no whitespace issues (leading/trailing whitespace is actually tolerated), no partial matches.

int("42")      # Returns 42
int("  42  ")  # Returns 42 (whitespace stripped)
int("-17")     # Returns -17

# These all raise ValueError
int("3.14")    # Fails - contains decimal point
int("42abc")   # Fails - contains non-numeric characters
int("")        # Fails - empty string

The string-to-integer conversion also supports different bases:

int("1010", 2)   # Binary → 10
int("ff", 16)    # Hexadecimal → 255
int("0xff", 16)  # Also works with prefix → 255
int("77", 8)     # Octal → 63

From Booleans: Simple Mapping

Booleans convert predictably: True becomes 1, False becomes 0.

int(True)   # Returns 1
int(False)  # Returns 0

This works because Python’s bool is actually a subclass of int.

Converting to Floats with float()

The float() function converts values to floating-point numbers. It’s more forgiving than int() in some ways, but introduces its own considerations.

From Integers and Strings

float(5)       # Returns 5.0
float(-17)     # Returns -17.0
float("3.14")  # Returns 3.14
float("42")    # Returns 42.0 (integers in string form work fine)
float("-0.5")  # Returns -0.5

Special Float Values

Python supports special float values that you’ll encounter in scientific computing and when parsing certain data formats:

float("inf")    # Positive infinity
float("-inf")   # Negative infinity
float("nan")    # Not a Number

# Scientific notation works too
float("1e10")   # Returns 10000000000.0
float("2.5e-3") # Returns 0.0025

Precision Considerations

Floating-point arithmetic has inherent precision limitations. This isn’t a Python quirk—it’s how IEEE 754 floating-point works across all languages.

float("0.1") + float("0.2")  # Returns 0.30000000000000004, not 0.3

For financial calculations or anywhere precision matters, use the decimal module instead:

from decimal import Decimal
Decimal("0.1") + Decimal("0.2")  # Returns Decimal('0.3')

Converting to Strings with str()

The str() function is the most forgiving converter. Nearly everything in Python has a string representation.

str(123)      # Returns "123"
str(3.14159)  # Returns "3.14159"
str(True)     # Returns "True"
str(False)    # Returns "False"
str(None)     # Returns "None"
str([1, 2])   # Returns "[1, 2]"

Common Use Case: String Concatenation

Python doesn’t implicitly convert types for string concatenation. This is a deliberate design choice that prevents ambiguity.

age = 25
# This fails with TypeError
# message = "Age: " + age

# Explicit conversion required
message = "Age: " + str(age)  # "Age: 25"

F-Strings: The Modern Approach

For most string formatting needs, f-strings handle conversion automatically and offer better readability:

age = 25
balance = 1234.5678

# F-strings convert automatically
message = f"Age: {age}"                    # "Age: 25"
formatted = f"Balance: ${balance:.2f}"    # "Balance: $1234.57"

F-strings call str() implicitly on the interpolated values, but also support format specifications for precise control.

Converting to Booleans with bool()

Boolean conversion in Python follows the concept of “truthiness.” Every value is either truthy (converts to True) or falsy (converts to False).

Falsy Values

These values evaluate to False:

bool(0)        # False - zero integer
bool(0.0)      # False - zero float
bool("")       # False - empty string
bool([])       # False - empty list
bool({})       # False - empty dict
bool(())       # False - empty tuple
bool(set())    # False - empty set
bool(None)     # False - None
bool(False)    # False - obviously

Truthy Values

Everything else is truthy:

bool(1)          # True
bool(-1)         # True - any non-zero number
bool(0.0001)     # True
bool("False")    # True - non-empty string (the content doesn't matter!)
bool([0])        # True - non-empty list (even if it contains falsy values)
bool(" ")        # True - string with just a space is non-empty

The bool("False") case catches many developers off guard. The string "False" is truthy because it’s a non-empty string. Python doesn’t interpret the string’s content.

Practical Application: Conditional Checks

Understanding truthiness lets you write cleaner conditionals:

# Instead of this
if len(my_list) > 0:
    process(my_list)

# Write this
if my_list:
    process(my_list)

# Instead of this
if user_input != "":
    validate(user_input)

# Write this
if user_input:
    validate(user_input)

Error Handling in Type Conversion

Type conversion with external data is a primary source of runtime errors. Defensive programming is essential.

Common Exceptions

# ValueError: invalid literal
int("abc")      # ValueError
float("not_a_number")  # ValueError

# TypeError: wrong argument type
int(None)       # TypeError
int([1, 2, 3])  # TypeError

Safe Conversion Pattern

Create utility functions that handle conversion failures gracefully:

def safe_int(value, default=0):
    """Convert to int, returning default on failure."""
    try:
        return int(value)
    except (ValueError, TypeError):
        return default

def safe_float(value, default=0.0):
    """Convert to float, returning default on failure."""
    try:
        return float(value)
    except (ValueError, TypeError):
        return default

# Usage
safe_int("42")       # Returns 42
safe_int("invalid")  # Returns 0
safe_int(None, -1)   # Returns -1

Validation Before Conversion

For user input, validate before converting:

def parse_positive_integer(value):
    """Parse a string as a positive integer with validation."""
    if not isinstance(value, str):
        raise TypeError(f"Expected string, got {type(value).__name__}")
    
    value = value.strip()
    
    if not value:
        raise ValueError("Empty string provided")
    
    if not value.isdigit():
        raise ValueError(f"Invalid integer format: {value}")
    
    result = int(value)
    
    if result <= 0:
        raise ValueError(f"Expected positive integer, got {result}")
    
    return result

Practical Applications

Parsing CSV Data

Real-world data is messy. Here’s a pattern for parsing CSV rows with mixed types:

def parse_user_record(row):
    """Parse a CSV row into a structured user record."""
    # row format: name, age, balance, is_active
    if len(row) != 4:
        raise ValueError(f"Expected 4 fields, got {len(row)}")
    
    name, age_str, balance_str, active_str = row
    
    return {
        "name": name.strip(),
        "age": safe_int(age_str.strip(), default=None),
        "balance": safe_float(balance_str.strip(), default=0.0),
        "is_active": active_str.strip().lower() in ("true", "1", "yes"),
    }

# Usage
record = parse_user_record(["Alice", "30", "1500.50", "true"])
# {'name': 'Alice', 'age': 30, 'balance': 1500.5, 'is_active': True}

API Response Processing

When consuming external APIs, never trust the data types:

def process_api_response(data):
    """Safely extract and convert API response fields."""
    return {
        "id": int(data.get("id", 0)),
        "price": float(data.get("price", "0")),
        "quantity": safe_int(data.get("quantity"), default=1),
        "available": bool(data.get("in_stock", False)),
    }

Type conversion is foundational to Python programming. Master these patterns, understand the edge cases, and always handle external data defensively. Your applications will be more robust, and your debugging sessions will be shorter.

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.