Magic Methods are the special methods which gives us the ability to access built in syntactical features such as ‘<’, ‘>’, ‘==’, ‘+’ etc.. You must have worked with such methods without knowing them to be as magic methods. Magic methods can be identified with their names which start with __ and ends with __ like etc. These methods are also called Dunder Methods, because of their name starting and ending with Double Underscore (Dunder). __init__, __call__, __str__ Now there are a number of such special methods, which you might have come across too, in Python. We will just be taking an example of a few of them to understand how they work and how we can use them. 1. __init__ print( ) obj = AnyClass() : class AnyClass : def __init__ () "Init called on its own" The first example is and as the name suggests, it is used for initializing objects. Init method is called on its own, ie. whenever an object is created for the class, the __init__ method is called on its own. __init__, The output of the above code will be given below. Note how we did not call the init method and it got invoked as we created an object for class AnyClass. Init called on its own 2. __add__ Let’s move to some other example, gives us the ability to access the built in syntax feature of the character +. Let’s see how, __add__ self.some_var = var print( ) self.some_var + other_obj.some_var obj1 = AnyClass( ) obj2 = AnyClass( ) obj1 + obj2 : class AnyClass : def __init__ (self, var) : def __add__ (self, other_obj) "Calling the add method" return 5 6 As we use the + character, it will call the method. Now observe the , it expects the second argument to be , and hence we have the access to add not just of the other object but any other variable as well. The output would be, __add__ __add__ other_obj some_var "Calling the add method" 11 Similar to , we can have __add__ __eq__(self, other_obj)Defines behavior for the equality operator, ==. __ne__(self, other_obj)Defines behavior for the inequality operator, !=. __lt__(self, other_obj)Defines behavior for the less-than operator, <. __gt__(self, other_obj)Defines behavior for the greater-than operator, >. __le__(self, other_obj)Defines behavior for the less-than-or-equal-to operator, <=. __ge__(self, other_obj)Defines behavior for the greater-than-or-equal-to operator, >=. 3. __repr__ It is used to represent the object. It gives all the representation of all the information of the object. We will understand more about it in the example later. If we create an object of the class from the previous example, and do or it will return AnyClass repr(obj) print(obj) '<__main__.AnyClass object at 0x0000025B8FB75048>' Let’s add the __repr__ method to our AnyClass, and see the ‘magic’. self.some_var = var print( ) obj = AnyClass( ) print(obj) : class AnyClass : def __init__ (self, var) : def __repr__ (self) f"AnyClass with some_var value as " {self.some_var} 5 The output of the above example will be, AnyClass some_var value with as 5 Now, let’s use these magic methods and compare Tesla Model 3 and Ford Mustang Lets create a class Car and define these magic methods to get the ability to use the operators and compare the Car’s attributes such as Top Speed, Horsepower and Price. self.name = name self.manufacturer = manufacturer self.horsepower = horsepower self.top_speed = top_speed self.cost = cost self.length = length print( ) print( ) print( ) : class Car : def __init__ (self, name, manufacturer, horsepower, top_speed, cost, length) : def __sub__ (self, other) f"Difference In Price: " {self.cost - other.cost} f"Difference in Horsepower: " {self.horsepower - other.horsepower} f"Difference in Top Speed: " {self.top_speed - other.top_speed} : def __len__ (self) return f" m" {self.length} If we run this program and command, tesla = Car(name= , manufacturer= , horsepower= , top_speed= , cost= , length= ) ford = Car(name= , manufacturer= , horsepower= , top_speed= , cost= , length= ) ford - tesla len(ford) len(tesla) 'Model 3' 'Tesla' 283 129 35000 4.69 'Mustang Mach E' 'Ford' 282 132 25100 4.72 Will return us, Difference In Price: $ Difference Horsepower: Difference Top Speed: m m 8895 in -1 in 3 4.72 4.69 The ‘-’ operator gave us the difference in price, power and speed, it’s nothing less of a ‘magic’ if you don’t know how it works. But now we do know, and lets implement other methods. And gave us the lengths of the cars ie. the length attribute of the Car object. len self.name = name self.manufacturer = manufacturer self.horsepower = horsepower self.top_speed = top_speed self.cost = cost self.length = length print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) print( ) tesla = Car(name= , manufacturer= , horsepower= , top_speed= , cost= , length= ) ford = Car(name= , manufacturer= , horsepower= , top_speed= , cost= , length= ) : class Car : def __init__ (self, name, manufacturer, horsepower, top_speed, cost, length) : def __add__ (self, other) f"Combined Price: $ " {self.cost + other.cost} f"Combined Horsepower: " {self.horsepower + other.horsepower} : def __sub__ (self, other) f"Difference In Price: " {self.cost - other.cost} f"Difference in Horsepower: " {self.horsepower - other.horsepower} f"Difference in Top Speed: " {self.top_speed - other.top_speed} : def __repr__ (self) return f" " {self.manufacturer} {self.name} : def __eq__ (self, other) f"Top Speed: " {self.top_speed == other.top_speed} f"Horsepower: " {self.horsepower == other.horsepower} f"Price: $ " {self.cost == other.cost} : def __gt__ (self, other) f"Top Speed: " {self.top_speed > other.top_speed} f"Horsepower: " {self.horsepower > other.horsepower} f"Price: $ " {self.cost > other.cost} : def __lt__ (self, other) f"Top Speed: " {self.top_speed < other.top_speed} f"Horsepower: " {self.horsepower < other.horsepower} f"Price: $ " {self.cost < other.cost} : def __le__ (self, other) f"Top Speed: " {self.top_speed <= other.top_speed} f"Horsepower: " {self.horsepower <= other.horsepower} f"Price: $ " {self.cost <= other.cost} : def __ge__ (self, other) f"Top Speed: " {self.top_speed >= other.top_speed} f"Horsepower: " {self.horsepower >= other.horsepower} f"Price: $ " {self.cost >= other.cost} : def __ne__ (self, other) f"Top Speed: " {self.top_speed != other.top_speed} f"Horsepower: " {self.horsepower != other.horsepower} f"Price: $ " {self.cost != other.cost} : def __str__ (self) return f" with top speed starting at " {self.manufacturer} {self.name} {self.horsepower} {self.top_speed} {self.cost} : def __len__ (self) return f" m" {self.length} 'Model 3' 'Tesla' 283 129 35000 4.69 'Mustang Mach E' 'Ford' 282 132 43895 4.72 By this program, we will be able to run commands such as,tesla == ford tesla != ford, tesla < ford etc.. Note this might not be something that you will have to do in real life but this is one of the examples to showcase how we can make use of the built in features of Python, and understand the concepts behind them.