Python Type Casting With int, float, and str

In Python, type casting is not a low-level memory reinterpretation, but an object-oriented instantiation process driven by built-in class constructors like int(), float(), and str(). When you cast a value using one of these functions, Python evaluates the input, checks for compatible internal protocols via special "dunder" methods, or passes the data to specialized CPython conversion algorithms. This article explains how Python implements type casting under the hood, detailing the roles of the data model protocols, string parsing routines, and fallback mechanisms.

Constructors Instead of Traditional Casts

Unlike compiled languages like C or C++, where casting often reinterprets raw bits in memory or instructs the compiler to handle an address differently, Python treats int, float, and str as built-in classes.

Calling int(x) is syntactically identical to instantiating an object of class int. When invoked, the type's __new__ and __init__ methods are triggered. The constructor inspects the type of argument x and selects the appropriate internal execution path: delegation to an object's protocol method or invocation of low-level string parsing routines.

The Protocol-Based Delegation Model

Python relies heavily on duck typing and the Python Data Model. When a built-in constructor receives an existing object, it attempts to call a corresponding magic method defined on that object's class.

1. How int() Works

When int(x) is called:

2. How float() Works

When float(x) is executed:

3. How str() Works

When str(x) is executed:

Low-Level Parsing and Numeric Conversion

When converting strings to numbers, Python cannot rely on dunder methods because strings do not intrinsically know how to compute arbitrary numeric representations. Instead, CPython relies on internal C routines:

Implementing Casting in Custom Classes

Because type casting relies on the Python Data Model, user-defined classes can define how they behave when passed to int(), float(), and str():

class Temperature:
    def __init__(self, celsius):
        self.celsius = float(celsius)

    def __int__(self):
        return int(self.celsius)

    def __float__(self):
        return self.celsius

    def __str__(self):
        return f"{self.celsius}°C"

temp = Temperature(21.8)

print(int(temp))    # Output: 21 (calls __int__)
print(float(temp))  # Output: 21.8 (calls __float__)
print(str(temp))    # Output: 21.8°C (calls __str__)

Error Handling

Python enforces strict type safety during casting operations: