
Python has been one of the widely used and adopted languages, especially in the world of Machine Learning. There are no second thoughts in giving Python recognition of the most versatile language. Not only it is used to work with backend data but it can be also used to do front-end UI. Python has the tools that can do magic. However, the goal for many of them has always to accomplish the goal without thinking of Best Practices and efficiency.
With the aim to accomplish the goal, we end up writing n number of functions that will be called and get the work done. Some of these interconnected functions can be defined using one just single class. Fortunately, Python is Object-Oriented Programming(OOP) and can be used to solve problems by creating objects. Because Python is OOP, using reusable code, and avoiding redundancy is the biggest advantage.
class
Starting with the most important component that will really make it OOP is by defining class. class is basically a template to create objects. Think of a Pizza class that will tell the ingredients, types, size, etc. A simple class would look like:

init
init is the initializer method that is run as soon as we call the class. Here type_ variable was assigned the value "veggie" as soon as the class was initiated.

Let’s say we create a method that will print the requested pizza. This is called an instance method because they are called on instance object obj. The best practice is to define a variable under this method, so it can be accessed anywhere inside the class. It is not required by Python as to where should the instance attributes should be defined within a class.
call
call is run as soon as a method is called. It basically takes action once the object is initiated. call is useful when an instance needs to often change state.

We can see that the default value of shape is ’round’. However, I was able to change the shape by passing a value to the object after initiating it. Try passing empty brackets and check the output!
repr
repr is mainly used to see the values assigned to our variables. It can be defined as below:

Even though repr is considered as "official" string representation of an object this is mainly used for debugging, mainly used by developers.
str
str is quite similar to repr above. str can be overridden and allows more customization unless like repr which cannot be.

As seen above, unless like repr, the object needs to be passed to the print function to display the variables. str is the opposite of reprand is considered as an "informal" string representation of an object. It is used mainly for creating output for regular users.
dict
Python has an internal dictionary called dict that holds all the internal variables. It is a simple way to inspect the internal details of the variables.

One can also change the variables directly by using dict attribute as below:

slots
slots is quite similar to dict as shown above. This is one of the best features, often unused by the Python community. If the data is passed to init and used mainly for storing data, slots can help to optimize the performance of the class. Below is how to use it:
To dive a bit deep in detail, dict wastes a lot of RAM. This is a great way to tell Python not to use dict and only use a fixed set of attributes. For heavy RAM work, some people have seen a reduction of 40–50% in RAM usage[2] by using slots.
static method:
We saw briefly how we can create methods to get a specific task done. Some methods, do not need to be modified or pass any class argument necessarily, to be used. It makes sense for them to be part of the class but not the object of the class. In other words, they know nothing about the class state. Such methods are known as static method. Below is a small example:

As we see above, we can directly use static method without even initiating the class. We define such methods using @staticmethod. We mainly use to create utility functions.
class method:
The class method is different from the static method. Here, the class method can access or modify class state. We pass cls as an argument that points to the class and not the object instance – when the method is called.

As we see above, one can use the method separately, but it needs all the arguments that the class to which it belongs expects. The size was determined as "medium" based on the entered number. We define them using @classmethod.
Conclusion:
These are some of the important aspects that I’ve learned over a period of time. If one wants to really write better Python code, it is important to understand and implement these "best practices". It might be difficult to understand in the first place, but the more you code and try to use them the more clear you will understand their importance. Best practices help in the long-term maintainability of the codebase. A good foundation laid integrating good design principles will not only make future development easier but also help other users/team members to reuse or do advancements using the same code.
References:
2. https://book.pythontips.com/en/latest/slotsmagic.html
If there are any concepts you think I missed and should add please feel free to comment! Comments are appreciated!
Please sign up for a membership if you want to become a Medium member and enjoy reading articles without any limits. Medium will share a portion with me for any members who sign up using the above link! Thanks.