Complete guide to Python's __sub__ method covering operator overloading, vector math, and custom subtraction behavior.
Last modified April 8, 2025
This comprehensive guide explores Python’s sub method, the special method that implements subtraction operation (-). We’ll cover basic usage, vector math, custom behavior, and practical examples.
The sub method is called to implement the subtraction operator (-). When you write x - y, Python attempts to call x.sub(y).
Key characteristics: it must accept two parameters (self and other), returns the result of subtraction, and can be overridden to customize behavior. It works with both built-in and custom types.
Here’s a simple class implementing sub to demonstrate basic subtraction behavior between objects of the same type.
basic_sub.py
class Number: def init(self, value): self.value = value
def __sub__(self, other):
if isinstance(other, Number):
return Number(self.value - other.value)
return NotImplemented
a = Number(10) b = Number(3) result = a - b print(result.value) # Output: 7
This example shows how to implement basic subtraction between Number objects. The sub method checks if the other operand is also a Number.
Returning NotImplemented tells Python to try the reverse operation (rsub) if available. This maintains operator flexibility.
The sub method is commonly used for mathematical operations like vector subtraction, where we subtract corresponding components.
vector_sub.py
class Vector: def init(self, x, y): self.x = x self.y = y
def __sub__(self, other):
if isinstance(other, Vector):
return Vector(self.x - other.x, self.y - other.y)
return NotImplemented
def __repr__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(5, 7) v2 = Vector(3, 2) result = v1 - v2 print(result) # Output: Vector(2, 5)
This Vector class implements component-wise subtraction. The sub method creates and returns a new Vector with subtracted components.
The repr method provides a readable string representation of the vector, making debugging and output clearer.
sub can handle operations between different types by checking the type of the other operand and implementing appropriate behavior.
mixed_sub.py
class Currency: def init(self, amount, currency_code): self.amount = amount self.currency_code = currency_code
def __sub__(self, other):
if isinstance(other, Currency):
if self.currency_code != other.currency_code:
raise ValueError("Cannot subtract different currencies")
return Currency(self.amount - other.amount, self.currency_code)
elif isinstance(other, (int, float)):
return Currency(self.amount - other, self.currency_code)
return NotImplemented
def __repr__(self):
return f"{self.amount} {self.currency_code}"
usd1 = Currency(100, “USD”) usd2 = Currency(30, “USD”) print(usd1 - usd2) # 70 USD print(usd1 - 15) # 85 USD
This Currency class allows subtraction between Currency objects of the same type and also supports subtracting numbers directly from the amount.
The method includes type checking and currency validation to ensure only meaningful operations are performed. This makes the class more robust.
When the left operand doesn’t support subtraction with the right operand, Python tries the reverse operation using rsub.
reverse_sub.py
class Temperature: def init(self, value): self.value = value
def __sub__(self, other):
if isinstance(other, Temperature):
return Temperature(self.value - other.value)
return NotImplemented
def __rsub__(self, other):
if isinstance(other, (int, float)):
return Temperature(other - self.value)
return NotImplemented
def __repr__(self):
return f"{self.value}°C"
temp = Temperature(10) result1 = temp - Temperature(3) # Uses sub result2 = 20 - temp # Uses rsub print(result1) # 7°C print(result2) # 10°C
This example shows both normal and reverse subtraction. When Python encounters 20 - temp, it first tries int.sub which fails.
Then it tries temp.rsub(20) which succeeds. This makes the class more flexible when used with built-in types.
The isub method implements in-place subtraction (-=) which modifies the object instead of creating a new one.
inplace_sub.py
class Account: def init(self, balance): self.balance = balance
def __sub__(self, other):
if isinstance(other, (int, float)):
return Account(self.balance - other)
return NotImplemented
def __isub__(self, other):
if isinstance(other, (int, float)):
self.balance -= other
return self
return NotImplemented
def __repr__(self):
return f"Account(balance={self.balance})"
acc = Account(100) acc -= 30 # Uses isub print(acc) # Account(balance=70)
The isub method modifies the object’s state directly and returns self. This is more efficient than sub when you don’t need a new object.
For mutable objects, implementing isub can provide better performance by avoiding unnecessary object creation.
Type checking: Always validate operand types in sub
Return NotImplemented: For unsupported operations
Implement rsub: For reverse operation support
Consider isub: For efficient in-place operations
Maintain consistency: Ensure subtraction follows mathematical rules
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.