class, constructor and magic methods !
Tags: python, oop, tutorial, beginners
Published: 2023-08-10 13:00:00

## syntax
Let's begin by analyzing the provided class syntax:

```python
class Fraction:
    def __init__(self, f1, f2):
        self.f1 = f1
        self.f2 = f2
```

Now, let's deconstruct this syntax to achieve a deeper comprehension and provide a more exhaustive explanation:

- The keyword `class` is employed for the creation of a class.
- The name of this class is `Fraction`, and it adheres to the Pascal case naming convention, where the initial letter of each compound word in a variable is capitalized.
- The keyword `def` is utilized for the definition of a function.
- `__init__` is a magic/dunder(short for "double underscore") method known as the constructor. We will delve into this concept further.
- We encounter the parameter `self` in this context. Its significance will be discussed in the upcoming section.
- The parameters `f1` and `f2` symbolize inputs.

Among these terms, certain ones may stand out as new to you, such as `__init__`, `self`, `self.f1`, and `self.f2`.

## constructor

Let's initiate the explanation by elaborating on the `__init__` method. This method is referred to as the constructor and incorporates the parameter `self`. The constructor holds the distinction of being a special or dunder (double underscore) method.

For the time being, remember that any method commencing and concluding with two underscores is denoted as a magic or dunder method.

## Method ?
A method is essentially a function defined within a class, distinguishing it from a regular `function`.

- So, what sets the `__init__` method apart ?
 
Unlike other methods, this particular method is automatically executed whenever an instance/object of the class is created. Put differently, there's no need to explicitly call upon `__init__` to initiate its execution; it is invoked every time an object of the class comes into existence.

However, the question arises: how do we go about creating objects?

Recall from the [previous blog](https://dev.to/coderatul/best-blog-on-oop-1c2e) that datatypes themselves are classes. Let's create an `object` of the `list` class:

```python
a = ["this will blow your mind"]
b = list("this will blow your mind")
print(type(a))  # <class 'list'>
print(type(b))  # <class 'list'>
```

Ordinarily, when crafting a list, you may have used object literals (An object literal is a syntactical way to define and create objects directly within the code, without the need for explicit class definitions or constructors). 

However, you also have the option of creating a list or list object by utilizing the class name, as demonstrated in the creation of list `b` as a `reference variable`.

Upon the creation of lists `a` and `b`, the `__init__` constructor of the list class would have executed 

With a grasp of the constructor's purpose, let's now delve into its necessity.

The constructor serves as a primary means to initialize variables or attributes within a class. It furnishes significant flexibility, enabling customization of its behavior to align with specific requirements.

For instance, in the scenario of designing a class to represent fractions, the `__init__` method can be employed to impose constraints, such as preventing a denominator from being assigned a value of zero.

## Magic Methods

In Python, there are special methods known as "magic methods," which are distinguished by their double underscores at the start and end of their names. 

These methods, often referred to as dunder methods, are intended to be internally invoked by the class itself in response to specific actions, rather than being directly called by the programmer. An illustrative example is the addition of two numbers using the + operator, which triggers the invocation of the `__add__()` method behind the scenes.

Python's built-in classes include a variety of magic methods. By using the `dir()` function, you can explore the assortment of magic methods inherited by a given class. For instance, consider the `str` class, where the `dir()` function facilitates the listing of attributes and methods associated with it.

```python
a = 1 + 2
print(a)  # 3
```

While executing the above code, Python interprets that we are attempting to add two objects of the `int` class, namely `a` and `b`. Consequently, under the `int` class, it searches for the `__add__` magic method, which dictates how the addition operation should be computed for those objects.