Interface type for OOP in python

To create templates for objects in an OOP project, you have to use abc and its decorator @abstractmethod.

I was thinking of symplifying this process by introducing a new interface keyword. It should be a soft keyword to ensure backward compatibility (I found more than 3M python code with the interface symbole on GitHub : Code search results · GitHub )

With this keyword, this code

from abc import abstractmethod, ABCMeta

class MyInterface(metaclass=ABCMeta):
    @abstractmethod
    def myMethod(self, val:int, arg:str) -> str:
        raise NotImplementedError # or pass, ellipsis, ...

will become

from typing import Callable

interface MyInterface:
    myMethod:Callable[[int, str], str]

This should improve code readability, and maintainability for future revisions.

As far as I read your suggestion, it’s just syntactic sugar for the above. Note that the standard way to write this is

from abc import ABC, abstractmethod

class MyInterface(ABC):
    @abstractmethod
    def my_method(self, val: int, arg: str) -> str:
        ...

which is slightly simpler than your initial code.

I claim that this is good enough, in particular also on the background that Protocols are a typing-based (and duck-typing compatible) alternative, and thus the need/usage for abstract classes as formalized interface is reduced.

Note also that introducing a new keyword is a very high bar. If anything you could argue for

@interface
class MyInterface:
    my_method:Callable[[int, str], str]

which would be similiar to dataclasses, and you can implement this as a third party package without needing to change the language. Though I think specifying method signatures through

 @abstractmethod
    def my_method(self, val: int, arg: str) -> str:
        ...

is more readable than through the type my_method: Callable[[int, str], str].

3 Likes

I love this approach which can be less problematic with old codebases

I think there are couple ideas in your post. One of them is using the Callable annotation instead of method declarations. Have you considered that the Callable annotation is significantly more limited? For example, it doesn’t support keyword-only or positional-only parameters, defaulted parameters, parameter names, etc.

The other idea whereby interface marks a class that contains all abstract methods could be implemented using a base class that overrides __init_subclass__ and inherits from ABC (if you want).

1 Like

yeah that was the point to make this built-in in order to limit imports and simplify OOP. This idea come from JAVA as i have JAVA courses at school

Are you sure you need an abstract base class instead of a protocol?

from typing import Protocol

class MyInterface(Protocol):
    def myMethod(self, val: int, arg: str) -> str:
        ...

It’s still more verbose than your proposal, but not so verbose that I think a change to the grammar is warranted. (Though it would be nice to be able to use myMethod : Callable[...] in place of a complete, do-nothing function definition. That wouldn’t require a change to the grammar, just a change, I think, to how type checkers check protocol conformance.)

2 Likes

yeah that was the point to make this built-in in order to limit imports and simplify OOP. This idea come from JAVA as i have JAVA courses at school

Note that Python is not Java, in particular typing concepts are fundamentally different, which is why related patterns shouldn’t be transferred 1:1. Interfaces in Java are needed to have an implementation-free API definition that can be implemented by multiple classes. Since Python uses duck-typing, every class can just define the relevant functions and they can be used interchangably. We can work perfectly fine without interfaces. In fact, interfaces (as a base class with only abstract methods) would limit duck-typing because every implementor would need to derive from the base class (and thus depend on it). The down-side of duck-typing is that the API is not spelled out explicitly, so it’s difficult to know what the actual API is and whether my implementation fully complies. This is where Protocols come into play. They are an implementation-free duck-typing compatible API specification, which is validated through static type checking.

2 Likes