Python Basic Object Oriented Programming
Tags: python, oop
Published: 2020-10-07 17:12:06

**Warning:** This is a long tutorial, (also, this is my first tutorial, so it will probably not be good :)

Object Oriented Programming, OOP, is a way to model objects, it is useful for simulations. Before Object Oriented Programming, long pieces of code were written with functions. Functions have their strengths, but they tend to make your code look like a nice bowl of _spaghetti_.

![Spaghetti Code](https://dev-to-uploads.s3.amazonaws.com/i/h8a0y16ft8hswbtonhwx.jpeg)

Delicious, but no one can read it, because no one can read _spaghetti_.

However, another way to code came up, this method was less like spaghetti and more like neat, organized **breadsticks**.

![Good Breadsticks, MMM](https://dev-to-uploads.s3.amazonaws.com/i/pil7we1bsqq22d8bxrjm.jpeg)

Now let's imagine that we are a kitchen making company. We are also excellent programmers, so we are writing some code to help with the kitchen making process. We need to come up with a generic template for the kitchen. We have to **type** (typing is important, do not copy and paste) this code in.

```python
class GenericKitchen:
    
    def __init__(self, numOfApplicances, kitchenSize):
        self.numberOfApplicances = numOfApplicances
        self.kitchenSize = kitchenSize # kitchenSize is a tuple (width, height)
        print("I have been inited")

    def getInventory(self):
        kitchenWidth = self.kitchenSize[0]
        kitchenHeight = self.kitchenSize[1]
        print(f"Number of appliances: {self.numberOfApplicances}")
        print(f"Size of kitchen: {kitchenWidth} by {kitchenHeight}")
```
#### Breakdown:

```python
class GenericKitchen:
```

This is just used to tell python that `GenericKitchen` is a class

```python
def __init__(self, numOfAppliances, kitchenSize):
        self.numberOfAppliances = numOfAppliances
        self.kitchenSize = kitchenSize 
        print("I have been inited") 
```

The `__init__` method (a.k.a function) is a dunder method (**d**ouble **under**score). A dunder method is a type of function that allows built the class to interact with built in functions, however this `__init__` method is important because it allows . `self` tells python that this variable is part of the `GenericKitchen` class (more on this later).

```python
def getInventory(self):
        kitchenWidth = self.kitchenSize[0]
        kitchenHeight = self.kitchenSize[1]
        print(f"Number of appliances: {self.numberOfApplicances}")
        print(f"Size of kitchen: {kitchenWidth} by {kitchenHeight}")
```
Get Inventory is a function that inherits from `self` and therefore inherits all the variables from self. `kitchenWidth` and `kitchenHeight` are local variables, meaning that they cannot be used outside of the function.

To call a class, type:

```python
kitchenDimensions = (100, 100)
# ^^^^^^^^^^^^^^^ 
# Don't use such long names, they are a pain to type
normalKitchen = GenericKitchen(5, kitchenDimensions)

>>>  I have been inited
```
You might be wondering, why did python print `I have been inited` on the screen if you didn't call the function. Well, the reason why is because the `__init__` method is a dunder method, it's function is to do something when the class is called. It looks similar to,
 
```python
number = list("hello")
print(number)

>>>  ["h", "e", "l", "l", "o"]
```

Why, because `list` is a class. The list's `__init__` method generates a list and returns it to the variable number. 

## Self
Self is a very important concept to understand (understand yourself too :)

`self` is the container for all the variables shared by the class. For example:

```python
class RandomClass():
    def __init__(self):
        self.name = "Jim"
        self.printName()
        self.name = "Tomi"

    def printName(self):
        print(self.name)

    def setAge(self):
        self.age = 14

rand = RandomClass()
rand.printName()

>>> Jim
    Tomi
```

What is happening is that with each class definition, `self` is defined with it. `self` then becomes the container for everything declared in the class that is shared among the class. When `printName` takes the argument `self`, it takes all of the variables and functions associated with `self` such as `self.age` and `self.setAge`. When we pass a class to a variable, what is happening is that `self` gets passed along with it, `self` will then equal the variablename

# Conclusion
Classes are important to know to both model things, and for cleaner code. Breadstick Code is better than Spaghetti Code (I just made Breadstick Code Up). Classes are defined using `class ClassName`. `self` is where all the instances of the class are contained.