6.4. Extending Operators#

Python has a lot of built-in operators:

  • Arithmetic operators: +, -, *, /, //, %, **

  • Comparison operators: ==, !=, >, <, >=, <=

  • Logical operators: and, or, not

  • Bitwise operators: &, |, ^, ~, <<, >>

  • Assignment operators: =, +=, -=, *=, /=, //=, %=, **=, &=, |=, ^=, <<=, >>=

  • Identity operators: is, is not

  • Membership operators: in, not in

These operators work with built-in types. It is possible to extend them to work with custom classes. This is done by defining special methods in the class.

6.4.1. Special / Magic Methods#

Special methods are methods that are defined by using double underscores. They are also called magic methods.

We have already seen one of them: __init__. This method is called when an instance of the class is created and is used to initialize the instance.

Similarly, we can define methods to extend the behavior of operators. For example, we can define a method to extend the behavior of the + operator for our custom Point class.

6.4.2. Example 1: Extending the + Operator#

Note that the + operator is used to add two numbers, concatenate two strings, and merge two lists. However, it does not work by default with custom classes.

class Point: 
    def __init__(self, x, y): 
        self.x = x 
        self.y = y 

p1 = Point(1, 2)
p2 = Point(1, 2)

p1 + p2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [1], in <cell line: 9>()
      6 p1 = Point(1, 2)
      7 p2 = Point(1, 2)
----> 9 p1 + p2

TypeError: unsupported operand type(s) for +: 'Point' and 'Point'

In order to extend the behavior of the + operator for our custom class, we need to define a method called __add__.

This method should take two arguments:

  1. self: is the object on the left side of the + operator.

  2. other: is the object on the right side of the + operator.

The method should return the result of the operation.

Let’s see an example.

class Point: 
    def __init__(self, x, y): 
        self.x = x 
        self.y = y 

    def __add__(self, other): 
        x = self.x + other.x 
        y = self.y + other.y 
        return Point(x, y)
    
p1 = Point(1, 2)
p2 = Point(1, 2)

result = p1 + p2

print(result)#, result.x, result.y)
Hello World

It works! We can now add two Point objects using the + operator.

6.4.3. Example 2: String Representation#

When we print an object, we get something like <__main__.Point object at 0x7f3e3c3e3f10>. This is the default string representation of the object.

Similar to changing the default behavior of + operator, we can change how the object is represented as a string. We can do this by defining another special method called __str__.

class Point: 
    def __init__(self, x, y): 
        self.x = x 
        self.y = y 

    def __add__(self, other): 
        x = self.x + other.x 
        y = self.y + other.y 
        return Point(x, y)

    def __str__(self): 
        return "(%s, %s)" % (self.x, self.y)
    
p1 = Point(1, 2)

print(p1)
(1, 2)

6.4.4. Example 3: Extending the == Operator#

We can also extend the behavior of the == operator. This is done by defining a method called __eq__. This method should take two arguments: self and other. It should return True if the two objects are equal and False otherwise.

Let’s see an example.

class Point: 
    def __init__(self, x, y): 
        self.x = x 
        self.y = y 

    def __add__(self, other): 
        x = self.x + other.x 
        y = self.y + other.y 
        return Point(x, y)

    def __str__(self): 
        return "(%s, %s)" % (self.x, self.y)
    
p1 = Point(1, 2)
p2 = Point(1, 2)

p1 == p2
False

By default, two objects are equal if they refer to the same memory location. We can change this behavior by defining equality based on the values of attributes of the object.

We can do so by defining the __eq__ method. This method should return True if the x and y attributes of the two objects are equal and False otherwise.

class Point: 
    def __init__(self, x, y): 
        self.x = x 
        self.y = y 

    def __add__(self, other): 
        x = self.x + other.x 
        y = self.y + other.y 
        return Point(x, y)

    def __str__(self): 
        return "(%s, %s)" % (self.x, self.y)

    def __eq__(self, other): 
        return self.x == other.x and self.y == other.y
    
p1 = Point(1, 2)
p2 = Point(1, 2)

p1 == p2
True

6.4.5. List of Operator Overloading Methods#

The following table lists the operator overloading examples in Python. These examples show how to use the operator overloading methods.

Operator

Example

Method

Description

+

1 + 2

__add__

Addition

-

1 - 2

__sub__

Subtraction

*

1 * 2

__mul__

Multiplication

/

1 / 2

__truediv__

Division

//

1 // 2

__floordiv__

Floor Division

%

1 % 2

__mod__

Modulo

**

1 ** 2

__pow__

Exponentiation

<<

1 << 2

__lshift__

Bitwise Left Shift

>>

1 >> 2

__rshift__

Bitwise Right Shift

&

1 & 2

__and__

Bitwise AND

^

1 ^ 2

__xor__

Bitwise XOR

|

1 | 2

__or__

Bitwise OR

==

1 == 2

__eq__

Equality

!=

1 != 2

__ne__

Inequality

<

1 < 2

__lt__

Less Than

<=

1 <= 2

__le__

Less Than or Equal To

>

1 > 2

__gt__

Greater Than

>=

1 >= 2

__ge__

Greater Than or Equal To

()

f(1, 2)

__call__

Call

[]

a[1]

__getitem__

Index

[]

a[1] = 2

__setitem__

Index Assignment

[]

del a[1]

__delitem__

Index Deletion