A Realistic Look at Python Interfaces: Part I
Tags: python, beginners, tutorial, objectorientedprogramming
Published: 2023-03-17 12:17:19

---
title: A Realistic Look at Python Interfaces: Part I
published: true
date: 2023-01-15 21:25:49 UTC
tags: python, beginners, tutorial, objectorientedprogramming
canonical_url: https://albexl.hashnode.dev/a-realistic-look-at-python-interfaces-part-i
---

In this series of articles, we are going to be talking about **interfaces** in Python. Interfaces are a powerful resource to use in several real-life scenarios.

Because of that, we are going to approach learning them by using an example that is very likely to occur in **real life**. Even if this exact case does not happen exactly as we will show, it is easy to find similar cases and use similar solutions to the ones we are going to be talking about.

So, let's dive in!

## Real-Life Problem and Motivation

Suppose there is a **Research Center** that is conducting some important experiments. This Research Center would like to verify the access to its facilities. For that reason, it has a list of **visitors** authorized to enter. These **visitors** can be **persons** or **vehicles**. For the persons, it is only needed to store their **identity number** and **name**. And for the **vehicles** , it is only needed to store their **plate number** and the **type of vehicle** **(car, bus, or truck)**. We are asked to implement an access verification mechanism for the Research Center.

As we can see, this scenario is likely to happen in real life. Many institutions need to keep track of the visitors they have to their facilities, and need to be able to tell if a certain person or vehicle is allowed to enter it or not.

Let's see how we can make an initial solution to this problem using **object-oriented programming** in Python.

## First Approach

We need to start by creating a way to represent all the elements involved in this problem. On the one hand, we have **persons** and **vehicles** , and on the other hand, we have the **research center**. The first ones are the visitors, and the latter is the entity responsible for handling the access verifications.

Let's create our first solution.

### The Person Class

To represent a **Person** we will create a class that contains two attributes:

- An **id** attribute, which is of type **string**. This attribute is unique for every person.

- A **name** attribute, also a **string**.

A possible implementation in Python would be like this:

```
class Person:

    def __init__ (self, id: str, name: str):
        self.id = id
        self.name = name

    def __str__ (self) -> str:
        return self.id

```

This is a simple class, just for representational purposes. Because of that, it does not have any methods except for the special **\_\_str\_\_** to give a more human-readable representative string as its identifier.

### The Vehicle Class

Similar to the above example, to represent a **Vehicle** we will also create a class with two attributes:

- A **license plate** attribute, which is of type **string** and it is unique for every vehicle.

- A **vehicle type** attribute, which will be an **enum** type, since we only have three possible choices: car, bus, or truck.

An example of this class would be the following:

```
from enum import Enum

class VehicleType(Enum):

    AUTO = 1
    TRUCK = 2
    BUS = 3

class Vehicle:

    def __init__ (self, license_plate: str, vehicle_type: VehicleType):
        self.license_plate = license_plate
        self.vehicle_type = vehicle_type

    def __str__ (self) -> str:
        return self.license_plate

```

Once again, since this class is just for representational purposes, it will not have any methods except the **\_\_str\_\_** method, which we can use to easily identify our **vehicle** instances.

### The Research Center Class

Now that we know what our **visitor** classes look like, it is time for us to figure out a way to handle access verifications properly. For this reason, we are going to create a third class: the **Research Center**.

This class needs to have the capacity of checking if a **person** or **vehicle** can access it. Let's see one way to achieve this.

Let's create a **Research Center** class that will consist of the following:

- An **allowed\_persons** attribute, which will be a list of **persons** , as defined above. This list will contain all the **persons** allowed to enter the research center.

- An **allowed\_vehicles** attribute, which will be a list of **vehicles** , as defined above. Similar to the **allowed\_persons** list, this one will contain all the **vehicles** allowed to enter the research center.

- An **add\_person** method. This will add a new **person** to the list of allowed persons.

- An **add\_vehicle** method. This will add a new **vehicle** to the list of allowed vehicles.

- A **verify\_person\_access** method. This one will check if a particular **person** can access the research center.

- A **verify\_vehicle\_access** method. This one will check if a particular **vehicle** can access the research center.

As we can see, this class is more complex than the **person** or **vehicle** classes. It contains attributes as well as methods to handle the addition of new visitors and check the access of a particular visitor as well. An example of this class in Python would be like this:

```
class ResearchCenter:

    def __init__ (self):
        self.allowed_persons = []
        self.allowed_vehicles = []

    def add_person(self, person: Person):
        self.allowed_persons.append(person)

    def add_vehicle(self, vehicle: Vehicle):
        self.allowed_vehicles.append(vehicle)

    def verify_person_access(self, person: Person) -> bool:
        for registered_person in self.allowed_persons:
            if registered_person.id == person.id:
                return True
        return False

    def verify_vehicle_access(self, vehicle: Vehicle) -> bool:
        for registered_vehicle in self.allowed_vehicles:
            if registered_vehicle.license_plate == vehicle.license_plate:
                return True
        return False

```

We should notice how the **verify\_person\_access** method iterates through the list of allowed persons and checks if any of them shares the same **id** as the person being checked. Similarly, the **verify\_vehicle\_access** does the same for the allowed vehicles, and checks against the **license\_plate** attribute.

Remember that we are assuming that these attributes are unique, so they are a correct way of uniquely identifying either persons or vehicles.

## Flaws of our First Approach

The solution above seems to handle this particular problem very well. It sure can add new **persons** or **vehicles** and check for the access of some particular **visitor** by comparing their identifying attributes against the allowed persons or vehicles, depending on the case. So, what is wrong with this approach?

Well, let's imagine that the research center suddenly realized that it has not been tracking the **animals** they use for regular experiments. They would like to have a mechanism that allows them to check if some specific animal is part of the list of allowed animals. How would we modify our solution so that it can handle this new type of visitor?

A natural answer would be to create an **Animal** class, with some **id** attribute, and add the corresponding **allowed\_animals** list and the **add\_animal** and **verify\_animal\_access** methods to our **Research Center** class. This way we handle the case of animals.

But, what if they are also not keeping track of **drones** or **robots** , or any other entity they consider should be verified for access?

We would have to add the corresponding classes to represent these new entities and also add methods and properties to the **Research Center** class to handle the tracking and access checks.

These constant changes in the **Research Center** class could lead to introducing errors in our program. And this happens because we are letting all the responsibility for checking the access to the "almighty" **Research Center** class.

## Conclusions

So far we have seen how to approach a real-life problem using **object-oriented programming**. We have seen how to create classes and use them together to create a **correct solution** which still has some design **issues**.

So, how can we address these issues? That will be the subject of the **Part II** of this series of articles. In the meantime, feel free to reach me and tell me about how would you solve this problem using **object-oriented programming**. A little hint is on the title of this article itself!

If you want to check a more complete version of the code examples shown in this article you can do it [here](https://gist.github.com/albexl/033fa4afa3afbb9b95f2300f0ab3bdd5).

If you enjoy this article, please show your support by reacting, commenting, or just spending a few minutes **thinking** about the topics exposed here. Don't be a passive reader, think about what you read and share your thoughts. See you soon!

* * *

👋 Hello, I'm Alberto, **Software Developer at** [**doWhile**](https://dowhile.se/), Competitive Programmer, Teacher, and Fitness Enthusiast.

🧡 If you liked this article, consider sharing it.

🔗 [All links](https://bio.link/albexl) | [Twitter](https://twitter.com/albe_xl) | [LinkedIn](https://www.linkedin.com/in/albexl/)