Interfaces in Python: not truly an interface, just a convention.
Tags: python, programming, beginners, oop
Published: 2022-09-14 22:39:07

In the Python context, different from strongly typed programming languages such as Java, interface isn’t a thing. There is no `interface` keyword. But you can try to implement something similar to an interface. In Python we could try to represent an interface creating a kind of specialized class which would be like an abstract class that contains only abstract methods. It has no implementations at all, just the definition of abstract methods.
By convention you don't have to but you can use the "Interface" word on the name of the class you created to be the interface. Then it will be explicit that it's an interface.
Like the example below:

```Python
class GameInterface:
    def start(self):
        raise NotImplementedError("You must implement the start method.")

    def play(self):
        raise NotImplementedError("You must implement the play method.")

    def reset(self):
        raise NotImplementedError("You must implement the reset method.")
```

As you can see, it works similarly as an interface but it’s not truly an interface.
Once in Python there are no `implements` or `interface` keywords and we’re creating something by convention, to use the interface we created, we will pass it as a parent class. Because in fact it is a class. So we can write something like that:

```Python
class Pinball(GameInterface):
    def start(self):
        print("Start Pinball")
    
    def play(self):
        print("Play Pinball")

    def reset(self):
        print("Reset Pinball")

class Tetris(GameInterface):
    def start(self):
        print("Start Tetris")
    
    def play(self):
        print("Play Tetris")

    def reset(self):
        print("Reset Tetris")

class PacMan(GameInterface):
    def start(self):
        print("Start Pac-Man")
    
    def play(self):
        print("Play Pac-Man")

    def reset(self):
        print("Reset Pac-Man")
```

As I mentioned at the beginning of the post, in other programming languages that interfaces can be really implemented not just as a convention, if you don't implement in the class using the interface one of the interface methods probably you won't even be allowed to go on and run the code because some required method is not implemented yet. Different from our Python example that we need to raise errors in order to warn who is implementing the interface that are methods which need to be implemented.

**And a note:** if your class will inherit another class as a parent class, besides the “interface” one, it’s important to pass first the actual parent class followed by the class you created to be the interface. So let's say you want to create another parent class that implements many other attributes and methods besides the methods defined in the interface. It's important to pass the classes in the mentioned order:

```Python
class GameInterface:
    pass

class BaseGame:
    pass

class Tetris(BaseGame, GameInterface):
    pass
```

---

## Interface as a Type

Going back to our first example, let's say there is a program to run the games we created. And the program runs a start, a play and a reset method. It doesn't matter which instance game is passed to it to be executed, the program needs to ensure that all games have these methods so it won't crash. And to ensure that, the idea of having an interface is basically using it as a type to be passed to the program that will run the games. Then it will ensure that all required methods are there because all games implement the same interface.
See the example below:

```Python
class GameInterface:
    def start(self):
        raise NotImplementedError("You must implement the start method.")

    def play(self):
        raise NotImplementedError("You must implement the play method.")

    def reset(self):
        raise NotImplementedError("You must implement the reset method.")

class Pinball(GameInterface):
    def start(self):
        print("Start Pinball")
    
    def play(self):
        print("Play Pinball")

    def reset(self):
        print("Reset Pinball")

def run_game(game):
    game.start()
    game.play()
    if some_condition:
      game.reset()

```

So comparing again to typed languages, in TypeScript for example there is a way you can ensure that the type of the parameter passed to `run_game` is the expected type. You would have to use the created interface as a type between the parenthesis (like any other data types such as integer, string, etc). In TypeScript you would write something like this:

```TypeScript
function run_game(game: Game) {
    game.start()
    game.play()
    if ("some condition") {
        game.reset()
    }
}
```

where game is a parameter of type Game (which is the Game interface).

In Python we can use a similar syntax, it will not complain.
So we can write something similar to what we already wrote above. In Python it would be like that:

```Python
def run_game(game: GameInterface):
    game.start()
    game.play()
    if some_condition:
      game.reset()
```
So if we create an instance of any of our games and pass it as an argument to the run_code method, it will run perfectly because all of them have the required methods implemented by the `GameInterface`.

## And what if we create a method for a specific class of our games and call it inside our `run_game` method?

Well in Python there would be no complaint and the program would crash, raising an error if you pass an instance from a class that doesn't have the specific method. But in Java or TypeScript it wouldn't even be allowed to pass the specific method inside the `run_code` method because it would complain before you run the code. Once the parameter type is defined, Java or TS would enforce that all methods called inside `run_code` are implemented in the `Game` interface.
See both examples below:

Python example when you pass an instance from a class containing the specific method:
![First Python example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/svca4g8ygh6ttmrhqnv1.png)

Python example when you pass an instance from a class that doesn't have the specific method. It crashes:

![Second Python example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jrp9jk2at2gzsrrvuqbe.png)

TypeScript example:
![TypeScript example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6a1j7erdc1v0i0wp5xjr.png)

The main thing to notice when comparing the examples above is what I've mentioned: in the first example you see there is no complaint from Python when I write a method that doesn't belong to the specified interface but only to a specific class. The program doesn't crash because I passed an instance from the specific class. But in the second example you can see in the console the error because I passed an instance from a class that doesn't contain the specific method.
And finally, in the third example, you see the difference of using a strongly typed language such as TypeScript that complains when you write a method that doesn't belong to the specified interface. It doesn't even let me run it.