Type Casting in Python — Convert Between Data Types Safely

Sanjeev SharmaSanjeev Sharma
5 min read

Advertisement

Introduction

Why This Matters

Type casting — converting values from one data type to another — is one of the most common operations in Python. When you read user input, all values come in as strings and must be converted. When working with APIs, JSON values may need to be cast to match your data model. When processing CSV files, numeric columns arrive as strings that need to become integers or floats.

Understanding both implicit conversion (which Python does automatically) and explicit conversion (which you control) prevents TypeError and ValueError at runtime. Knowing the edge cases — what fails, what loses precision, and how to validate before casting — makes your code more robust.

This is also fundamental knowledge for data pipelines, form processing, and any code that handles user-supplied data.

Implicit Type Conversion

Python automatically converts types in some expressions to prevent data loss.

# int + float → float
result = 5 + 2.5
print(result)        # 7.5
print(type(result))  # <class 'float'>
 
# int + complex → complex
z = 3 + (1 + 2j)
print(z)             # (4+2j)
print(type(z))       # <class 'complex'>
 
# bool is a subtype of int
print(True + 1)      # 2
print(False + 10)    # 10
print(True * 5)      # 5

Explicit Type Conversion — int()

# String to int
print(int("42"))      # 42
print(int("  10 "))  # 10 (strips whitespace)
 
# Float to int (truncates, does not round)
print(int(3.9))       # 3
print(int(-3.9))      # -3
 
# Bool to int
print(int(True))      # 1
print(int(False))     # 0
 
# Different bases
print(int("0b1010", 2))   # 10 (binary)
print(int("FF", 16))      # 255 (hexadecimal)
print(int("777", 8))      # 511 (octal)
 
# Fails
try:
    int("hello")
except ValueError as e:
    print(e)  # invalid literal for int() with base 10: 'hello'

Explicit Type Conversion — float()

print(float(42))         # 42.0
print(float("3.14"))     # 3.14
print(float("1e3"))      # 1000.0
print(float(True))       # 1.0
print(float("inf"))      # inf
print(float("-inf"))     # -inf
 
# Fails
try:
    float("abc")
except ValueError as e:
    print(e)  # could not convert string to float: 'abc'

Explicit Type Conversion — str()

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]'
 
# For custom objects, define __str__
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __str__(self):
        return f"({self.x}, {self.y})"
 
print(str(Point(3, 4)))  # (3, 4)

Explicit Type Conversion — bool()

Falsy values: 0, 0.0, "", [], {}, set(), None, False

print(bool(0))         # False
print(bool(0.0))       # False
print(bool(""))        # False
print(bool([]))        # False
print(bool({}))        # False
print(bool(None))      # False
 
print(bool(1))         # True
print(bool(-1))        # True
print(bool("0"))       # True — non-empty string
print(bool([0]))       # True — non-empty list

Converting Between Collections

# list, tuple, set conversions
numbers = [1, 2, 3, 2, 1]
 
t = tuple(numbers)          # (1, 2, 3, 2, 1)
s = set(numbers)            # {1, 2, 3} — deduplicated
l = list(s)                 # [1, 2, 3] (order not guaranteed)
back = sorted(list(s))      # [1, 2, 3]
 
# String to list of chars
chars = list("hello")       # ['h', 'e', 'l', 'l', 'o']
joined = "".join(chars)     # 'hello'
 
# Range to list
nums = list(range(5))       # [0, 1, 2, 3, 4]
 
# Dict from pairs
pairs = [("a", 1), ("b", 2)]
d = dict(pairs)             # {'a': 1, 'b': 2}

Safe Conversion Patterns

def safe_int(value, default: int = 0) -> int:
    try:
        return int(value)
    except (ValueError, TypeError):
        return default
 
print(safe_int("42"))      # 42
print(safe_int("hello"))   # 0
print(safe_int(None))      # 0
print(safe_int("3.7"))     # 0  — int() won't parse floats-as-strings
 
# Safe float-to-int
def to_int(value) -> int:
    try:
        return int(float(value))  # handles "3.7" → 3
    except (ValueError, TypeError):
        return 0
 
print(to_int("3.7"))   # 3

Common Mistakes

  • Using int("3.7") directly — raises ValueError; use int(float("3.7")) instead
  • Expecting int() to round — it always truncates toward zero
  • Forgetting that str(None) gives "None", not an empty string
  • Assuming bool("False") is False — any non-empty string is truthy
  • Converting large float to int when precision matters — use Decimal instead

Best Practices

  • Always wrap user input conversions in try/except with a meaningful error message
  • Use isinstance(value, int) to check type before converting
  • Use Decimal for monetary values — float arithmetic has precision issues
  • Validate string format before converting with str.isdigit() or str.isnumeric()
  • Use int(float(x)) to safely convert "3.7"-style strings to integers

Key Takeaways

  • Python's implicit conversion promotes types to prevent data loss (int → float, bool → int)
  • int() truncates floats — it does not round; use round() if rounding is needed
  • int("3.7") raises ValueError — convert to float first: int(float("3.7"))
  • bool() treats 0, "", [], {}, None as falsy; everything else is truthy
  • list(), tuple(), set(), dict() convert between collection types
  • Always wrap type conversions on untrusted input in try/except
  • Use Decimal for precise decimal arithmetic; float has IEEE 754 rounding issues

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro