Beautiful concepts in Python

Do you know everything in Python is an object? When you declare a variable of x and initialize it with the value of 3 for example x = 3. What Python did here in the background was that it creates an instance of class int which is the variable x you declared. You would now ask how, that's good.

To answer your question better, I will also ask you this, why do you think the result of checking the type of variable x brings out <class 'int'>?

That simply tells you that you are creating an object of the class int which you call variable x. For this reason, python only recognizes the variable as an object of class int but to you, it is only a variable and that is also cool.

Let me burst your brain some more, check this out!

1. x = 3
2. y = 5
3.
4. print(x + y) # output: 8
5.
6. x = '3'
7. y = '6'
8.
9. print(x + y) # output: '36'

I know you already know what output that simple code will print out but do you know what's going on in the background? let's cook something up with the explanation but first, you have to understand everything in Python is an object. This is actually getting interesting

The beautiful thing about Python is that when it encounters the first example code above, it will call a very beautiful magic method in the class int which is the __add__ method. This method will be called this way:

int.__add__(3, 5) # output: 8

The second example code will also call the __add__ method for the concatenation but it won't call it using the class of int but instead the class of str. Yes absolutely, class str also has the same magic method as the class int but works differently. This is how it will call it:

str.__add__(3,6) #output: '36'

You might be wondering why there's an error log to the output when you want to perform the addition of an int type with a string of int i.e 5 + '3' I hope the answer to that should now be cleared that there's no class that handles the operation between two different types (except float and int type because the int will be implicitly converted to a float before any operation is performed) which is why we always have to explicitly convert one type to the other before we perform operations on them

You can do more than you actually believe

Let's think of a scenario, you are requested to build an app for an auction using OOP. After all the planning, you would eventually need to create instances of the auctioneer class and perform operations on those instances to determine who wins amongst them. Can we do write our code this way for a quick comparison?

class Auctioneer:
    def __init__(self, name, amount):
        self.name = name
        self.amount = amount

auct1 = Auctioneer('John', 1000)
auct2 = Auctioneer('Rutherford', 3000)

if auct1 > auct2:
    print(f'{auct1.name} is the winner')
else:
    print(f'{auct2.name} is the winner')



######################## ERROR CODE #############################
Traceback (most recent call last):
  File "c:\Users\sodiq\Documents\Python Scripts\script.py", line 9, in <module>
    if auct1 > auct2:
TypeError: '>' not supported between instances of 'Auctioneer' and 'Auctioneer'

Interesting, the error above is telling us that the comparison operator is not supported between the instances of the class Auctioneer which is actually true for now because we are going to implement our own logical comparison operator on the class. But first, how does python handles the code above?

What python did here was, it called upon the class of the instances involved in the comparison like so:

Auctioneer.__gt__(auct1, auct2)

That was the code that ran in the background but there's nothing like that in our class which is why it resulted to an error. That means the > symbol is also a method (magic method) inside the class of the calling instance in question.

Do you now believe everything in python is an object?

The solution to the code above is to write include the beautiful magic method in our class. This method is what python will look for whenever it encounters something like that. Let's see how to make that happen

class Auctioneer:
    def __init__(self, name, amount):
        self.name = name
        self.amount = amount

    def __gt__(self, nextObj):
         if self.amount > nextObj.amount:
              return True
         else:
              return False

auct1 = Auctioneer('John', 1000)
auct2 = Auctioneer('Rutherford', 3000)

if auct1 > auct2:
    print(f'{auct1.name} is the winner')
else:
    print(f'{auct2.name} is the winner')

If you run the code, the result should be like so:

########## Output ###########
'Rutherford is the winner'

Is it not beautiful ☺️? I hope you have come to realize now that everything in python is object. However, the example code used above does not necessarily have to be put that way, you might choose a different approach and that's fine. I chose that to illustrate the interesting part of python. We can even decide to sort the instances based on the amount or name, the sky is the limit

Being that as it may, thanks for taking the time to read up till to this point. Hope to see you in the next one. Peace out! ✌️