Home > Back-end >  Achieving interface without inheritance in Python
Achieving interface without inheritance in Python

Time:10-23

I have a sorted linked list

class SortedLinkedList:
    # ...
    def insert(self, value: int):
        # ...
        if node.value > value:
            self.add_before(node, value)
        # ...

I would like to generalize the type of values that a Node can hold from only ints to any object that overloads the > operator by implementing the __gt__() magic method.

In other languages I would achieve this by using an Interface, but Python apparently has no analog. I've seen suggestions to fake interfaces by using abstract classes like

class Sortable(ABC):
    @abstractmethod
    def __gt__(self, other) -> bool:
        pass

class SortedLinkedList:
    # ...
    def insert(self, value: Sortable, node: Node):
        # ...

The problem is this approach requires extending and using subclasses from Sortable, which means types that already have > functionality like integers cannot be used

linkedlist.insert(5) # Pylance red squiggles
Argument of type "Literal[5]" cannot be assigned to
parameter "value" of type "Sortable" in function "insert"
  "Literal[5]" is incompatible with "Sortable" Pylance(reportGeneralTypeIssues) 

I understand that Interfaces are not necessary pre-runtime given Python's dynamic duck typing and implicit style. I am not a fan, and am opting to use available tooling like typing and Pylance to achieve a strictly typed developer experience.

I am also not looking to use runtime checks like .hasattr(value, '__gt__'). I'm wanting this to register on the type system/language server/IDE level, as expressivity, readability, and IDE intellisense are the main benefits of strict typing.

Is there any way to achieve this?

CodePudding user response:

What you're looking for is typing.Protocol.

class Sortable(Protocol):
    def __gt__(self, other) -> bool: ...

With this, any class that defines __gt__ will be detected as an implicit subtype of Sortable.

  • Related