Day 2: Object Oriented Programming (OOP)
Tags: python, tutorial, beginners
Published: 2023-02-10 09:00:00


## What I learnt

- Classes
- Objects
- Inheritance
- Encapsulation
- Abstraction


## Classes

A class is a blueprint for creating objects. A class defines the properties and behaviours that all objects of that class share.

### Example of a class with attributes

```python
    class User:
        def __init__(self, name, email, age):
            self.name = name
            self.email = email
            self.age = age

        def greeting(self):
            return f'My name is {self.name} and I am {self.age}'
```

#### Example of an object with attributes

```python
    user_1 = User('Jobizil','jobizil@email.com', 25)

    print(user_1.name)
    print(user_1.email)
    print(user_1.greeting())
```

### Class Methods

- init() => This method is used to initialize the attributes of an object
- self => This is a reference to the current instance of the class and is used to access variables that belong to the class
- \_\_init\_\_ () => This method is called automatically every time the class is being used to create a new object
- super() => This is used to access methods and properties of the parent class

#### Common Class Patterns

- Creating multiple objects && Creating a class method

```python
    class User:
        def __init__(self, name, email, age):
            self.name = name
            self.email = email
            self.age = age

        def greeting(self):
            return f'My name is {self.name} and I am {self.age}'

        def has_birthday(self):
            self.age += 1
            return f'Happy {self.age}th, {self.name}'


    # Init user object

    user_1 = User('Jobizil', 'jobizil@email.com', 25)

    print(user_1.age)
    print(user_1.greeting())
    print(user_1.has_birthday())
```

## Inheritance

Inheritance is a way to form new classes using classes that have already been defined. The newly formed classes are called derived classes, and the classes that we derive from are called base classes. 

```python
    class User:
        def __init__(self, name, email, age):
            self.name = name
            self.email = email
            self.age = age

        def greeting(self):
            return f'My name is {self.name} and I am {self.age}'

        def has_birthday(self):
            self.age += 1
            return f'Happy {self.age}th, {self.name}'


    class Customer(User):
        def __init__(self, name, email, age):
            super().__init__(name, email, age)
            self.balance = 0

        def set_balance(self, balance):
            self.balance = balance
            return self.balance

        def greeting(self):
            return f'My name is {self.name} and I am {self.age} and my balance is {self.balance}'


    # Init customer object
    customer_1 = Customer('Quill', 'quilltech57@gmail.com', 22)
    customer_1.set_balance(500)
    print(customer_1.greeting())
```

## Encapsulation

Encapsulation is the process of wrapping up data and methods into a single unit. This is done to prevent accidental modification of data. In Python, we denote private attributes using an underscore as the prefix i.e single \_ or double \_\_.

```python
    class User:
        def __init__(self, name, email, age):
            self.name = name
            self.email = email
            self.age = age

        def greeting(self):
            return f'My name is {self.name} and I am {self.age}'

        def has_birthday(self):
            self.age += 1
            return f'Happy {self.age}th, {self.name}'
```

## Abstraction

Abstraction is the process of hiding the implementation details from the user, only the functionality will be provided to the user. In Python, we use abstract classes and interfaces.

```python
    from abc import ABC, abstractmethod

    class User(ABC):
        def __init__(self, name, email, age):
            self.name = name
            self.email = email
            self.age = age

        def greeting(self):
            return f'My name is {self.name} and I am {self.age}'

        def has_birthday(self):
            self.age += 1
            return f'Happy {self.age}th, {self.name}'

        @abstractmethod
        def has_birthday(self):
            pass
```


### Simple exercise

```python

# Use the Cat class to create 3 cat objects
# Assign the objects to 3 variables of your choice
# Create a method that finds the oldest cat
# Print out: "The oldest cat is x years old.". x will be the oldest cat age by using the function in #4

class Cat:
    species = 'mammal'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def oldest_cat(*args):
        return max(args)

    def best_name(self):
        return f'{self.name} is the best name'


cat_1 = Cat('Tom', 5)
cat_2 = Cat('Jerry', 3)
cat_3 = Cat('Mickey', 7)

oldest_cat = Cat.oldest_cat(cat_1.age, cat_2.age, cat_3.age)

print(f'The oldest cat is {oldest_cat} years old.')

```

## Resources

You can learn more about OOP using the python official documentation [here](https://docs.python.org/3/tutorial/classes.html).