How To Compare Tesla and Ford Company By Using Magic Methods in Python

Written by shivambats | Published 2020/08/16
Tech Story Tags: python3 | python | python-programming | python-web-development | python-tutorials | python-top-story | python-tips | learn-python

TLDR Magic Methods are the special methods which gives us the ability to access built in syntactical features such as ‘ <’, ‘>’ and ‘+’ These methods are also called Dunder Methods, because of their name starting and ending with Double Underscore (Dunder) Magic methods can be identified with their names which start with __ and ends with __ like __init__. The output of the example will be, 'AnyClass with some_var value as {self.some_var} "via the TL;DR App

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 __init__, __call__, __str__ etc. These methods are also called Dunder Methods, because of their name starting and ending with Double Underscore (Dunder).
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__

class AnyClass:
    def __init__():
        print("Init called on its own")
obj = AnyClass()
The first example is __init__, 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.
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, __add__ gives us the ability to access the built in syntax feature of the character +. Let’s see how,
class AnyClass:
    def __init__(self, var):
        self.some_var = var
    def __add__(self, other_obj):
        print("Calling the add method")
        return self.some_var + other_obj.some_var
obj1 = AnyClass(5)
obj2 = AnyClass(6)
obj1 + obj2
As we use the + character, it will call the __add__ method. Now observe the __add__, it expects the second argument to be other_obj, and hence we have the access to add not just some_var of the other object but any other variable as well. The output would be,
"Calling the add method"
11
Similar to __add__, we can have
  1. __eq__(self, other_obj)Defines behavior for the equality operator, ==.
  2. __ne__(self, other_obj)Defines behavior for the inequality operator, !=.
  3. __lt__(self, other_obj)Defines behavior for the less-than operator, <.
  4. __gt__(self, other_obj)Defines behavior for the greater-than operator, >.
  5. __le__(self, other_obj)Defines behavior for the less-than-or-equal-to operator, <=.
  6. __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 AnyClass from the previous example, and do repr(obj) or print(obj) it will return
'<__main__.AnyClass object at 0x0000025B8FB75048>'
Let’s add the __repr__ method to our AnyClass, and see the ‘magic’.
class AnyClass:
    def __init__(self, var):
        self.some_var = var
def __repr__(self):
        print(f"AnyClass with some_var value as {self.some_var}")
obj = AnyClass(5)
print(obj)
The output of the above example will be,
AnyClass with some_var value 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.
class Car:
    def __init__(self, name, manufacturer, horsepower, top_speed, cost, length):
        self.name = name
        self.manufacturer = manufacturer
        self.horsepower = horsepower
        self.top_speed = top_speed
        self.cost = cost
        self.length = length
    def __sub__(self, other):
        print(f"Difference In Price: {self.cost - other.cost}")
        print(f"Difference in Horsepower: {self.horsepower -     other.horsepower}")
        print(f"Difference in Top Speed: {self.top_speed -   other.top_speed}")
    def __len__(self):
        return f"{self.length}m"
If we run this program and command,
tesla = Car(name='Model 3', manufacturer='Tesla', horsepower=283, top_speed=129, cost=35000, length=4.69)
ford = Car(name='Mustang Mach E', manufacturer='Ford', horsepower=282, top_speed=132, cost=25100, length=4.72)
ford - tesla
len(ford)
len(tesla)
Will return us,
Difference In Price: $8895
Difference in Horsepower: -1
Difference in Top Speed: 3
4.72m
4.69m
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 len gave us the lengths of the cars ie. the length attribute of the Car object.
class Car:
    def __init__(self, name, manufacturer, horsepower, top_speed, cost, length):
        self.name = name
        self.manufacturer = manufacturer
        self.horsepower = horsepower
        self.top_speed = top_speed
        self.cost = cost
        self.length = length

    def __add__(self, other):
        print(f"Combined Price: ${self.cost + other.cost}")
        print(f"Combined Horsepower: {self.horsepower + other.horsepower}")

    def __sub__(self, other):
        print(f"Difference In Price: {self.cost - other.cost}")
        print(f"Difference in Horsepower: {self.horsepower - other.horsepower}")
        print(f"Difference in Top Speed: {self.top_speed - other.top_speed}")

    def __repr__(self):
        return f"{self.manufacturer} {self.name}"

    def __eq__(self, other):
        print(f"Top Speed: {self.top_speed == other.top_speed}")
        print(f"Horsepower: {self.horsepower == other.horsepower}")
        print(f"Price: ${self.cost == other.cost}")

    def __gt__(self, other):
        print(f"Top Speed: {self.top_speed > other.top_speed}")
        print(f"Horsepower: {self.horsepower > other.horsepower}")
        print(f"Price: ${self.cost > other.cost}")

    def __lt__(self, other):
        print(f"Top Speed: {self.top_speed < other.top_speed}")
        print(f"Horsepower: {self.horsepower < other.horsepower}")
        print(f"Price: ${self.cost < other.cost}")

    def __le__(self, other):
        print(f"Top Speed: {self.top_speed <= other.top_speed}")
        print(f"Horsepower: {self.horsepower <= other.horsepower}")
        print(f"Price: ${self.cost <= other.cost}")

    def __ge__(self, other):
        print(f"Top Speed: {self.top_speed >= other.top_speed}")
        print(f"Horsepower: {self.horsepower >= other.horsepower}")
        print(f"Price: ${self.cost >= other.cost}")

    def __ne__(self, other):
        print(f"Top Speed: {self.top_speed != other.top_speed}")
        print(f"Horsepower: {self.horsepower != other.horsepower}")
        print(f"Price: ${self.cost != other.cost}")

    def __str__(self):
        return f"{self.manufacturer} {self.name} {self.horsepower} with top speed {self.top_speed} starting at {self.cost}"

    def __len__(self):
        return f"{self.length}m"


tesla = Car(name='Model 3', manufacturer='Tesla', horsepower=283, top_speed=129, cost=35000, length=4.69)
ford = Car(name='Mustang Mach E', manufacturer='Ford', horsepower=282, top_speed=132, cost=43895, length=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.

Published by HackerNoon on 2020/08/16