# Abstraction&#x20;

Abstraction is one of the fundamental concepts of object-oriented programming (OOP). It is the process of hiding the implementation details of an object and only showing its essential features to the outside world. Abstraction allows you to focus on what an object does rather than how it does it.

In Python, abstraction can be achieved through the use of abstract classes and interfaces. An abstract class is a class that cannot be instantiated and can only be used as a base class for other classes. An interface is a collection of abstract methods that define the behavior of an object, but do not provide any implementation.

The goal of abstraction is to reduce complexity by breaking down a system into smaller, more manageable parts, and to simplify the interface between those parts. By hiding implementation details, abstraction allows you to change the implementation without affecting the rest of the system.&#x20;

## Abstract Classes and Interfaces

In Python, abstraction can be achieved through abstract classes and interfaces.

### a. Abstract Classes&#x20;

An abstract class is a class that cannot be instantiated on its own and is meant to be subclassed by other classes. It serves as a blueprint for the subclasses to follow. An abstract class contains abstract methods that the subclasses must implement.

In Python, an abstract class can be defined using the `abc` module. The `abc` module provides the `ABC` class that can be used as a metaclass for defining abstract classes. An abstract method is defined using the `@abstractmethod` decorator.

Here is an example of an abstract class in Python:

```python
from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

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

In this example, the `Shape` class is an abstract class that defines two abstract methods, `area()` and `perimeter()`. Any subclass of `Shape` must implement these two methods. If a subclass of `Shape` fails to implement these methods, a `TypeError` will be raised at runtime.

To create a subclass of an abstract class, the subclass must implement all the abstract methods of the abstract class. Here is an example:

```python
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)
```

In this example, `Rectangle` is a subclass of `Shape` and it implements both `area()` and `perimeter()` methods. &#x20;

#### Creating Abstract Classes in Python&#x20;

In Python, abstract classes can be created using the `abc` (abstract base classes) module. This module provides the `ABC` class and the `abstractmethod` decorator that can be used to create abstract methods.

Here's an example of how to create an abstract class in Python:

```python
from abc import ABC, abstractmethod

class Shape(ABC):
    
    @abstractmethod
    def area(self):
        pass
    
    @abstractmethod
    def perimeter(self):
        pass
```

In the above code, we define an abstract class `Shape` that inherits from the `ABC` class. We also define two abstract methods `area()` and `perimeter()` using the `abstractmethod` decorator. These methods do not have any implementation in the abstract class, but they need to be implemented by any concrete class that inherits from the `Shape` class.

Any attempt to create an object of an abstract class will result in a `TypeError`.

```python
s = Shape() # This will raise a TypeError
```

We must create a concrete class that inherits from the abstract class and implements the abstract methods.

### b. Interfaces

In Python, there is no built-in support for interfaces. However, we can implement interfaces using abstract classes. An interface can be defined as an abstract class that contains only abstract methods. Any class that implements the interface must provide an implementation for all of the abstract methods.

Here's an example of an interface defined using an abstract class:

```python
from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass
    
    @abstractmethod
    def perimeter(self):
        pass
```

In this example, the `Shape` class is an abstract class that defines an interface for all shapes. It contains two abstract methods: `area` and `perimeter`. Any class that wants to implement the `Shape` interface must provide an implementation for both of these methods.

Here's an example of a class that implements the `Shape` interface:

```python
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height
    
    def perimeter(self):
        return 2 * (self.width + self.height)
```

In this example, the `Rectangle` class implements the `Shape` interface by providing an implementation for both the `area` and `perimeter` methods.&#x20;

#### Creating Interfaces in Python&#x20;

Python does not have a built-in interface keyword or syntax to create interfaces, but we can use abstract classes to define an interface. To create an interface in Python, we can create an abstract class with only abstract methods.

Here's an example of creating an interface using an abstract class:

```python
from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

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

In this example, we created an abstract class `Shape` that defines an interface for geometric shapes. The `Shape` class has two abstract methods `area()` and `perimeter()`, which every concrete shape class must implement.

To use this interface, we can create a concrete class that implements the abstract methods of the `Shape` interface:

```python
class Rectangle(Shape):
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

    def perimeter(self):
        return 2 * (self.length + self.width)
```

In this example, we created a concrete class `Rectangle` that implements the `Shape` interface by providing concrete implementations of the `area()` and `perimeter()` methods. Now, we can use this `Rectangle` class to create instances of rectangles and call the `area()` and `perimeter()` methods, knowing that they will be implemented according to the `Shape` interface.

\
When to Use Abstraction&#x20;
-----------------------------

Abstraction is particularly useful in situations where you want to hide the implementation details of a class or module from its users. By using abstraction, you can provide a simplified and more intuitive interface to your users, which can make it easier for them to work with your code.

For example, imagine you are developing a complex software system with many different modules and classes. If you were to expose the implementation details of each class to the rest of the system, it would be much harder for other developers to understand how your code works and how to use it effectively.

By using abstraction to hide the implementation details of each class, you can simplify the system's overall architecture and make it easier for other developers to work with. Additionally, abstraction can help you enforce good design principles like modularity and encapsulation, which can make your code more maintainable and easier to modify over time.<br>
