Quark's Outlines: Python Coercion Rules

Published: (February 21, 2026 at 07:13 AM EST)
4 min read
Source: Dev.to

Source: Dev.to

Overview

When you use a binary operator like +, -, or * in Python, the interpreter must decide how to combine two values that may come from different types. The process Python uses to find a common type or method is called coercion.

Python checks whether one object knows how to handle the operation. If it doesn’t, Python checks the other object. In special cases, objects can transform themselves to work better with others.

print(3 + 5.0)
# 8.0

Here Python automatically coerces the integer 3 to a float so the addition can be performed.

When you mix user‑defined objects, Python gives your class a chance to control how it combines with others. If your object defines __add__, Python will call that method first. If that fails, Python will try the other object’s __radd__ method.

In older versions of Python you could define a method called __coerce__ to suggest how two objects should be made compatible. This method was removed in Python 3, but the pattern still illustrates how Python thinks about mixing types.

class MyNumber:
    def __radd__(self, other):
        return f"Called with {other}"

print(5 + MyNumber())
# Called with 5

Python first tried 5.__add__(), which failed, then called MyNumber().__radd__(5).

Historical Timeline

YearMilestone
1960Type promotion in FORTRAN allowed combining integers and floats by converting smaller types.
1972Operator overloading in C++ gave user‑defined types control over operator behavior.
1991Python 0.9.0 introduced __coerce__ for implicit conversion before operations.
2000Rich comparison and binary methods like __add__ and __radd__ replaced __coerce__.
2008Python 3.0 removed __coerce__, leaving only method‑based coercion and implicit numeric promotion.
2025Operator behavior stabilised with __op__ and __rop__ methods for custom types and mixed operations.

Using Python Coercion Rules Correctly

Python lets you combine different values using arithmetic and other operators. The coercion rules help built‑in types (e.g., int, float) and user‑defined objects work together without explicit conversion.

Mixing Numeric Types

Problem: You want to add an integer and a float without manual conversion.
Solution: Python promotes the smaller type (int) to the larger type (float).

x = 7
y = 2.5
print(x + y)
# 9.5

Python internally converts 7 to 7.0 before performing the addition.

Defining Right‑Hand Addition (__radd__)

Problem: You need a class to respond when it appears on the right side of +.
Solution: Implement __radd__ in your class.

class Adder:
    def __radd__(self, other):
        return other + 10

a = Adder()
print(5 + a)
# 15

Python first tries 5.__add__(a), which fails, then calls a.__radd__(5).

Cooperative Binary Operations Between Two Custom Classes

Problem: Two custom objects should work together with +.
Solution: Python tries __add__ on the left operand first; if it fails, it falls back to __radd__ on the right operand.

class A:
    def __add__(self, other):
        return "A handles it"

class B:
    def __radd__(self, other):
        return "B handles it"

print(A() + B())
# A handles it

Since A.__add__ succeeds, B.__radd__ is not invoked.

String Formatting with %

Problem: Insert a value into a string using the % operator without writing custom formatting logic.
Solution: When the left operand of % is a string, Python applies its built‑in formatting rules.

name = "Ada"
print("Hello, %s!" % name)
# Hello, Ada!

The % operator bypasses other coercion mechanisms when formatting strings.

Sequence Repetition with *

Problem: Repeat a list or string a given number of times without an explicit loop.
Solution: Python defines a special rule for sequence * int.

print([1, 2] * 3)
print("ha" * 2)
# [1, 2, 1, 2, 1, 2]
# haha

If one operand is a sequence (list, tuple, str) and the other is an integer, * performs repetition.

0 views
Back to Blog

Related posts

Read more »

Python Check If Number is an Integer

python def is_intx: int | float | str | None: ''' Return True if x represents an integer value, otherwise False. Handles: - int, float, and numeric strings e.g....