Python allows us to customize the behavior of objects for common operations like addition, subtraction, comparison, etc. Being able to customize basic operators makes objects more expressive in terms of functionality. If you are familiar with object-oriented operator overloading from other programming languages (like C++), you would find this discussion very familiar!
We begin by providing a table that lists some of the operators that can be loaded in Python. The provided list is, by no means, complete. Please refer to your Python manual for additional operators.
Operator Method | Description | Example |
---|---|---|
__init__ | Called after object creation | obj = classObj() |
__del__ | Called before object deletion | del obj |
__eq__ | Equality operator | objA == objB |
__gt__ | Greater than operator | objA > objB |
__lt__ | Less than operator | objA < objB |
__add__ | Add to the object | objA + objB |
__sub__ | Subtract an object | objA - objB |
__mul__ | Multiply the object | objA * objB |
__div__ | Divide the object | objA / objB |
__iadd__ | Increments the object | objA += objB |
__isub__ | Decrements the object | objA -= objB |
__contains__ | Check if objB is present in objA | objB in objA |
__setitem__ | Put objB at indx in objA | objA[indx] = objB |
__getitem__ | Get objB stored at indx in objA | objB = objA[indx] |
__str__ | Printing object | print(obj) |
__len__ | Length property of object | len(obj) |
__and__ | Binary AND | objA & objB |
__or__ | Binary OR | objA | objB |
__xor__ | Binary XOR | objA ^ objB |
__iter__ | Iterator handle | it = iter(objA) |
__next__ | Next value for iteration | next(it) |
Next, we present two examples that illustrate operator overloading for some of the commonly used operators. The first example focuses on a simple object and explores comparison operators like less than, greater than, etc. The second example focuses on an object that represents a group of objects -- this allows us to explore list-like properties of indexing, getting the length of the object, and so on.
The first example provides operator overloading for the following operators: __eq__, __gt__, __lt__, __str__, and __del__. The example uses a simple class, bigCat, that models big cats in the wild. The class has four data attributes to capture various information about big cats: name, geographic location, scientific name, and weight of the cat.
In the example (provided below), the __eq__ method checks if two bigCat objects are same. If both objects have the same name and same scientificName, then they are declared equal. The __lt__ and __gt__ methods compare two bigCat objects by comparing their weight attribute. The example also adds a __str__ method; this method returns the string that is printed when we invoke the print function on the object. Lastly, it also customizes the __del__ method.
class bigCat(): def __init__(self, name, location, scientificName, weight): self.name = name self.location = location self.scientificName = scientificName self.weight = weight def __eq__ (self, rhs): if ((self.name == rhs.name) and (self.scientificName == rhs.scientificName)): return True else: return False def __gt__ (self, rhs): if (self.weight > rhs.weight): return True else: return False def __lt__ (self, rhs): if (self.weight < rhs.weight): return True else: return False def __str__ (self): varStr = "Name: " + str(self.name) varStr += ", Weight: " + str(self.weight) varStr += ", Location: " + str(self.location) varStr += ", Scientific Name: " + str(self.scientificName) return varStr def __del__ (self): print("Deleting this object (name: %s)" % (self.name)) if __name__ == "__main__": objBigCat1 = bigCat("Leopard", "South Africa", "Panthera pardus", 180) objBigCat2 = bigCat("Leopard", "China", "Panthera pardus", 200) #Test the __str__ method print(objBigCat1) print(objBigCat2) #Test the __eq__ method if (objBigCat1 == objBigCat2): print("objBigCat1 and objBigCat2 are same") else: print("objBigCat1 and objBigCat2 are different") #Test the __gt__ method if (objBigCat1 > objBigCat2): print("objBigCat1 is bigger than objBigCat2") else: print("objBigCat2 is bigger than objBigCat1") #Test the __lt__ method if (objBigCat1 < objBigCat2): print("objBigCat1 is smaller than objBigCat2") else: print("objBigCat2 is smaller than objBigCat1") #Test the __del__ method del objBigCat1 del objBigCat2
We provide the output below. As expected, since objBigCat2 has more weight than objBigCat1, the __lt__ operator confirms that objBigCat1 is less than objBigCat2. Likewise, the __gt__ operator confirms that objBigCat2 is greater than objBigCat1. Also, we add the two del statements towards the end to test the __del__ method. In reality, we can skip that since the objects would get deleted automatically once the program is done.
Name: Leopard, Weight: 180, Location: South Africa, Scientific Name: Panthera pardus Name: Leopard, Weight: 200, Location: China, Scientific Name: Panthera pardus objBigCat1 and objBigCat2 are same objBigCat2 is bigger than objBigCat1 objBigCat1 is smaller than objBigCat2 Deleting this object (name: Leopard) Deleting this object (name: Leopard)
We choose the second example such that it represents a collection of objects. This allows us to conveniently test operators like addition, indexing, and length. To be more precise, the example provides overloading for the following operators: __add__, __contains__, __setitem__, __getitem__, and __len__. It also has __str__ and __len__ operators that we saw in the earlier example. The example uses two classes: (a) a "lion" class to hold information about lions and (b) a "pride" class to hold information about a group of lions living together.
In the example, the __add__ method adds a lion object to a list (named "lions") in the pride object. The __contains__ method provides a check to see if a given lion object is present in the list owned by the pride object. It does so by going through all the elements present in the lions list of the objPride; if it finds an element that has the same name and weight, it declares that the passed object exists. The __setitem__ allows us to add an object, once again a lion object, to the pride object at a given index. On the other hand, the __getitem__ method helps us retrieve an object present at the passed index. Next, we customize the __len__ method to return the number of objects present in the lions list of the objPride.
class lion(): def __init__(self, name, weight): self.name = name self.weight = weight def __str__ (self): varStr = "Name: " + str(self.name) varStr += ", Weight: " + str(self.weight) return varStr def __del__ (self): print("Deleting this object (name: " + self.name + ")") class pride(): def __init__(self): self.lions = [] def __add__ (self, rhs): self.lions.append(rhs) return self def __contains__(self, rhs): for elem in self.lions: if ((elem.name == rhs.name) and \ (elem.weight == rhs.weight)): return True return False def __setitem__ (self, indx, rhs): self.lions[indx] = rhs def __getitem__ (self, indx): return self.lions[indx] def __len__ (self): return (len(self.lions)) def __str__ (self): varStr = "\nPrinting the pride:" for elem in self.lions: varStr += "\nName: " + str(elem.name) varStr += ", Weight: " + str(elem.weight) return varStr def __del__ (self): print("\nDeleting the pride object") if __name__ == "__main__": objLion2 = lion("Aslan", 500) objLion1 = lion("Mufasa", 400) objLion3 = lion("Simba", 20) objPride = pride() #Test the __add__ method objPride = objPride + objLion1 objPride = objPride + objLion2 objPride = objPride + objLion3 #Test the __str__ method print(objPride) #Test the __len__ method print("Total number of lions in the pride are: %d" % (len(objPride))) #Test the __contains__ method if (objLion3 in objPride): print("\nobjLion3 belongs to the objPride") else: print("\nobjLion3 does not belong to the objPride") objLion4 = lion("Nala", 15) if (objLion4 in objPride): print("\nobjLion4 belongs to the objPride") else: print("\nobjLion4 does not belong to the objPride") #Test the __getitem__ method oneLion = objPride[0] twoLions = objPride[0:2] print("\nPrinting OneLion:") print(oneLion) print("\nPrinting twoLions:") for elem in twoLions: print(elem) #Test the __settitem__ method objPride[0] = objLion4 print(objPride)
The output (provided below) confirms that we are able to use various list-like operators for our custom class. Here is the output:
Printing the pride: Name: Mufasa, Weight: 400 Name: Aslan, Weight: 500 Name: Simba, Weight: 20 Total number of lions in the pride are: 3 objLion3 belongs to the objPride objLion4 does not belong to the objPride Printing OneLion: Name: Mufasa, Weight: 400 Printing twoLions: Name: Mufasa, Weight: 400 Name: Aslan, Weight: 500 Printing the pride: Name: Nala, Weight: 15 Name: Aslan, Weight: 500 Name: Simba, Weight: 20 Deleting the pride object Deleting this object (name: Simba) Deleting this object (name: Aslan) Deleting this object (name: Nala) Deleting this object (name: Mufasa)