377
public interface IInterface
{
    void show();
}

 public class MyClass : IInterface
{

    #region IInterface Members

    public void show()
    {
        Console.WriteLine("Hello World!");
    }

    #endregion
}

How do I implement Python equivalent of this C# code ?

class IInterface(object):
    def __init__(self):
        pass

    def show(self):
        raise Exception("NotImplementedException")


class MyClass(IInterface):
   def __init__(self):
       IInterface.__init__(self)

   def show(self):
       print 'Hello World!'

Is this a good idea?? Please give examples in your answers.

Byte Commander
  • 6,506
  • 6
  • 44
  • 71
Pratik Deoghare
  • 35,497
  • 30
  • 100
  • 146
  • 1
    What would be the purpose for using an interface in your case? – Bandi-T Jan 23 '10 at 18:54
  • 81
    Frankly no purpose at all ! I just want to learn what to do when you need interfaces in python? – Pratik Deoghare Jan 23 '10 at 19:13
  • 34
    `raise NotImplementedError` is what `show`'s body should be -- makes no sense to raise a completely generic `Exception` when Python defines a perfectly specific built-in one!-) – Alex Martelli Jan 23 '10 at 20:30
  • 3
    Shouldn't __init__ call show() in IInterface (or raise the exception itself) so you can't instantiate an abstract interface? – Katastic Voyage Aug 20 '17 at 07:45
  • 1
    I can see some use for this... let's say you have an object that you want to ensure has a specific signature. With duck typing you can't guarantee that the object will be of the signature that you expect. Sometimes it might be useful to enforce some typing on dynamically typed properties. – K-Dawg Oct 11 '17 at 13:10
  • Dependency inversion (the D in the SOLID) is what interfaces are useful for. However, I have not noticed it mentioned in the answers below - but there are other answers https://stackoverflow.com/questions/61358683/dependency-inversion-in-python – Roman Susi Sep 25 '21 at 05:45
  • Wow, there's a lot of answers here by people who don't get why interfaces are useful :( – John Hunt Nov 12 '21 at 11:49
  • @AlexMartelli Shouldn't one use an Abstract Base Class (ABC) instead of manually raising `NotImplementedError` https://docs.python.org/3/library/abc.html – mteam88 May 09 '22 at 17:08
  • @mteam88, if a suitable ABC exists, subclassing it is surely good. If you have to create a custom ABC -- that's a higher level of involvement, and sometimes just raising is simpler, lighter-weight. – Alex Martelli May 09 '22 at 23:06
  • @AlexMartelli True. The ABC does require some boilerplate. – mteam88 May 10 '22 at 13:55

8 Answers8

246

As mentioned by other here:

Interfaces are not necessary in Python. This is because Python has proper multiple inheritance, and also ducktyping, which means that the places where you must have interfaces in Java, you don't have to have them in Python.

That said, there are still several uses for interfaces. Some of them are covered by Pythons Abstract Base Classes, introduced in Python 2.6. They are useful, if you want to make base classes that cannot be instantiated, but provide a specific interface or part of an implementation.

Another usage is if you somehow want to specify that an object implements a specific interface, and you can use ABC's for that too by subclassing from them. Another way is zope.interface, a module that is a part of the Zope Component Architecture, a really awesomely cool component framework. Here you don't subclass from the interfaces, but instead mark classes (or even instances) as implementing an interface. This can also be used to look up components from a component registry. Supercool!

Isma
  • 14,604
  • 5
  • 37
  • 51
Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
  • 18
    Could you elaborate on this? 1. How does one implement such an interface? 2. How can it be used to look up components? – geoidesic May 23 '18 at 14:26
  • 206
    "Interfaces are not necessary in Python. Except when they are." – Baptiste Candellier Feb 09 '19 at 18:01
  • 33
    interfaces are mostly used to have a predictable outcome / enforce correctness of members when passing objects around. it would be great if python supported this as an option. it would also allow development tools to have better intellisense – Sonic Soul Mar 19 '19 at 18:57
  • interfaces are about memory management, primarily. They enforce the condition that the instantiated class that implements the interface, will have a memory footprint or 'signature' that will allow the interpreter/compiler to know with certainty the size of the object. I guess this isn't so necessary in Python due to dynamic typing and duck typing. If you want to define an interface, use ABC https://docs.python.org/3/library/abc.html, with which one marks classes as implementing an interface and which can be easily extended to provide the zope registry functionality. – miller the gorilla Apr 17 '19 at 10:29
  • 84
    "This is because Python has proper multiple inheritance", who said interfaces are for multiple inheritance? – adnanmuttaleb Dec 14 '19 at 19:30
  • 4
    I did, in my answer above. – Lennart Regebro Dec 15 '19 at 21:51
  • 24
    People talking about interfaces in terms of multiple inheritance, memory footprint: what if I have a module that abstracts the filesystem. The backend can be the local filesystem, ram, or one of the many cloud storage systems. Would be nice to instantiate a class from such module and known that the object will have certain methods, regardless of the backend implemented. IOW, interfaces. Nothing to do with multiple inheritance, nothing to do with memory. – rodrigo-silveira Aug 23 '20 at 01:31
  • @rodrigo-silveira - you can easily simulate interfaces with abstract classes that all have abstract methods. But yes, it would be nice to have a dedicated concept. – Mindaugas Bernatavičius Jun 01 '21 at 13:54
  • 3
    I have the feeling that most python developers do not see the need for interfaces since, simply, they haven't work with them and hence seen the utility they provide. – Hector Ordonez Jul 10 '21 at 10:42
  • What is "proper" inheritance, I mean vs "inproper"? – g.pickardou Jul 31 '21 at 07:49
  • @g.pickardou Full multiple inheritance, that inherits actual implementations. Actual multiple inheritance. Multiple inheritance that is more than just pretense. Basically any multiple inheritance except the one that Java pretends to have. :-) – Lennart Regebro Aug 02 '21 at 07:48
  • 3
    @LennartRegebro: I am pretty sure Java (and C#) has no multiple inheritance, and neither are pretending they have. Inheritance vs being in "is a" relationship is two different things. Going forward implementing interface or inheriting from a class also two different things. – g.pickardou Aug 02 '21 at 14:14
  • @g.pickardou In Java Interfaces is the replacement for multiple inheritance. That's how you do it in Java. Yes, indeed it's not actually multiple inheritance. Hence me calling actual multiple inheritance "proper multiple inheritance" instead of the "faking it" that Java has with interfaces. Therefore, in Python, who has it, you don't need interfaces for that. You also, in Python have duck typing, so you don't need interfaces for that either. I hope this explains my answer. – Lennart Regebro Aug 05 '21 at 14:20
  • @LennartRegebro I'm currently maintaining PyPDF2 and we have the issue of recursive imports. We have 3 very heavy classes: `PdfReader`, `PdfWriter`, and `PageObject` (let's just call it `Page`). PdfReader has many methods that return `Page` instances and `Page` holds references to `PdfReader`. How would you deal with that issue? – Martin Thoma Oct 26 '22 at 20:25
  • Support the other commenters on this one. Interfaces are not related to multiple inheritance. They're an absolute necessity for creating clear abstractions and contracts between modules and components. – Wecherowski Oct 28 '22 at 21:30
  • 1
    "Not necessary" . This misses the point of interfaces: ensuring that a class implements certain methods and potentially delegating to subclasses to achieve it. – WestCoastProjects Nov 27 '22 at 05:19
  • @Shayne "Multiple inheritance—and all the problems it generates—has beed discarded from Java. The desirable features of multiple inheritance are provided by interfaces". Source: James Gosling, Henry McGilton, "The Java Language Environment", p28, 1995 – Lennart Regebro Jun 21 '23 at 00:09
  • Yes, but this doesnt answer the question. He didnt ask about multiple inheretance (which is not the same concept at all), he asked about interfaces. – Shayne Jun 23 '23 at 04:38
  • Notice how you can't even say what is wrong? But I could directly point out that the only claim you have made WAS flat out wrong? Maybe YOU don't understand the point? – Lennart Regebro Jul 05 '23 at 10:12
  • Fine. I'll explain it. Abstract Base classes specify inpleementations, Interfaces specify behaviors. The key is that interfaces are not implementation specific. If you have two libraries that specify the same interface, they are compatible, but if they specify identical, but different ABCs they are not compatible, as introspection will not reveal that compatibility. Which means on the primary task that interfaces are designed for, describing a protocol for an object, the ABC introduces dependencies which break interoperability. They are fundamentally different concepts. – Shayne Jul 16 '23 at 05:54
  • "Abstract Base classes specify inpleementations" No, they don't. They CAN have code, but that's not what they are for. They are to force a certain API. "f you have two libraries that specify the same interface, they are compatible " Which is indeed one the explicitly stated purposes of ABC's. Now you know. "the ABC introduces dependencies which break interoperability." That is a directly incorrect statement. – Lennart Regebro Aug 01 '23 at 17:36
165

Implementing interfaces with abstract base classes is much simpler in modern Python 3 and they serve a purpose as an interface contract for plug-in extensions.

Create the interface/abstract base class:

from abc import ABC, abstractmethod

class AccountingSystem(ABC):

    @abstractmethod
    def create_purchase_invoice(self, purchase):
        pass

    @abstractmethod
    def create_sale_invoice(self, sale):
        log.debug('Creating sale invoice', sale)

Create a normal subclass and override all abstract methods:

class GizmoAccountingSystem(AccountingSystem):

    def create_purchase_invoice(self, purchase):
        submit_to_gizmo_purchase_service(purchase)

    def create_sale_invoice(self, sale):
        super().create_sale_invoice(sale)
        submit_to_gizmo_sale_service(sale)

You can optionally have common implementation in the abstract methods as in create_sale_invoice(), calling it with super() explicitly in the subclass as above.

Instantiation of a subclass that does not implement all the abstract methods fails:

class IncompleteAccountingSystem(AccountingSystem):
    pass

>>> accounting = IncompleteAccountingSystem()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class IncompleteAccountingSystem with abstract methods
create_purchase_invoice, create_sale_invoice

You can also have abstract properties, static and class methods by combining corresponding annotations with @abstractmethod.

Abstract base classes are great for implementing plugin-based systems. All imported subclasses of a class are accessible via __subclasses__(), so if you load all classes from a plugin directory with importlib.import_module() and if they subclass the base class, you have direct access to them via __subclasses__() and you can be sure that the interface contract is enforced for all of them during instantiation.

Here's the plugin loading implementation for the AccountingSystem example above:

...
from importlib import import_module

class AccountingSystem(ABC):

    ...
    _instance = None

    @classmethod
    def instance(cls):
        if not cls._instance:
            module_name = settings.ACCOUNTING_SYSTEM_MODULE_NAME
            import_module(module_name)
            subclasses = cls.__subclasses__()
            if len(subclasses) > 1:
                raise InvalidAccountingSystemError('More than one '
                        f'accounting module: {subclasses}')
            if not subclasses or module_name not in str(subclasses[0]):
                raise InvalidAccountingSystemError('Accounting module '
                        f'{module_name} does not exist or does not '
                        'subclass AccountingSystem')
            cls._instance = subclasses[0]()
        return cls._instance

Then you can access the accounting system plugin object through the AccountingSystem class:

>>> accountingsystem = AccountingSystem.instance()

(Inspired by this PyMOTW-3 post.)

mrts
  • 16,697
  • 8
  • 89
  • 72
  • 5
    **Question:** What does the module-name "ABC" stand for? – Sebastian Nielsen Jan 09 '20 at 15:14
  • 7
    "ABC" stands for "Abstract Base Classes", see [official docs](https://docs.python.org/3/library/abc.html) – mrts Jan 13 '20 at 15:18
  • 1
    NB it's not enough to set the base class and decorate methods; the abstract methods must also raise `NotImplementedError`. I learned this the hard way in https://stackoverflow.com/a/38885553/5568265 – todofixthis Jun 04 '23 at 00:12
118

Using the abc module for abstract base classes seems to do the trick.

from abc import ABCMeta, abstractmethod

class IInterface:
    __metaclass__ = ABCMeta

    @classmethod
    def version(self): return "1.0"
    @abstractmethod
    def show(self): raise NotImplementedError

class MyServer(IInterface):
    def show(self):
        print 'Hello, World 2!'

class MyBadServer(object):
    def show(self):
        print 'Damn you, world!'


class MyClient(object):

    def __init__(self, server):
        if not isinstance(server, IInterface): raise Exception('Bad interface')
        if not IInterface.version() == '1.0': raise Exception('Bad revision')

        self._server = server


    def client_show(self):
        self._server.show()


# This call will fail with an exception
try:
    x = MyClient(MyBadServer)
except Exception as exc:
    print 'Failed as it should!'

# This will pass with glory
MyClient(MyServer()).client_show()
Peter Torpman
  • 1,281
  • 1
  • 8
  • 2
  • 46
    Yugghh, needing some module for what should be part of the language itself, or not used at all, IMO. – Mike de Klerk Mar 01 '19 at 09:48
  • 2
    do you mean: `if not server.version() == '1.0': raise ...`? I don't realy get this line. An explaination would be welcome. – Skandix Mar 18 '19 at 17:41
  • 4
    @MikedeKlerk I couldn't agree more. Just like the Python answer to typing; I shouldn't have to import a module to declare I want a type to be a type. The response to that is typically "well Python is dynamically typed", but that isn't an excuse. Java + Groovy solve this problem. Java for the static stuff, Groovy for the dynamic stuff. – ubiquibacon Jul 03 '19 at 21:36
  • 17
    @MikedeKlerk, the abc module is indeed built-in to python. It is a little more work to set up some of these patterns because they are largely unneeded in Python due to alternative patterns that are considered 'more Pythonic'. For the vast majority of developers, it would be as you said, 'not used at all'. However, acknowledging that there are some very niche cases that truly require these interfacing capabilities, the Python creators provided an easy-to-use API to make that possible. – David Culbreth Nov 21 '19 at 23:13
  • 1
    I'd argue that python has a policy (at least historically) of *not* doing stuff at the lannguage level. I don't know why, but it keeps the language a bit smaller and simpler. Even when they do have synactic magic, this is often represented as python "under the hood". (e.g. [__add__](https://docs.python.org/3/reference/datamodel.html#object.__add__) and friends versus [C++'s operator overloading](https://en.cppreference.com/w/cpp/language/operators)). As David points out above, there is still [one way to do it](https://peps.python.org/pep-0020/) as abc in the standard library. – Att Righ Sep 16 '22 at 10:59
  • Yeah Python has traditionally been rather conservative about adding syntax where a simple library could do it better. Thats changed a bit in recent times (keep in mind kids, Pythons probably the oldest dynamic language in popular use [now that basic is more or less dead] !) with the recent surge in popularity and the change in guard at the top of the PEP pile but generally python prefers to adapt the old over adding the new. – Shayne Jun 09 '23 at 02:19
103

I invite you to explore what Python 3.8 has to offer for the subject matter in form of Structural subtyping (static duck typing) (PEP 544)

See the short description https://docs.python.org/3/library/typing.html#typing.Protocol

For the simple example here it goes like this:

from typing import Protocol

class MyShowProto(Protocol):
    def show(self):
        ...


class MyClass:
    def show(self):
        print('Hello World!')


class MyOtherClass:
    pass


def foo(o: MyShowProto):
    return o.show()

foo(MyClass())  # ok
foo(MyOtherClass())  # fails

foo(MyOtherClass()) will fail static type checks:

$ mypy proto-experiment.py 
proto-experiment.py:21: error: Argument 1 to "foo" has incompatible type "MyOtherClass"; expected "MyShowProto"
Found 1 error in 1 file (checked 1 source file)

In addition, you can specify the base class explicitly, for instance:

class MyOtherClass(MyShowProto):

but note that this makes methods of the base class actually available on the subclass, and thus the static checker will not report that a method definition is missing on the MyOtherClass. So in this case, in order to get a useful type-checking, all the methods that we want to be explicitly implemented should be decorated with @abstractmethod:

from typing import Protocol
from abc import abstractmethod

class MyShowProto(Protocol):
    @abstractmethod
    def show(self): raise NotImplementedError


class MyOtherClass(MyShowProto):
    pass


MyOtherClass()  # error in type checker
Peter and the Wolf
  • 1,321
  • 1
  • 9
  • 14
  • how do we decorate a static method to get the same effect? Note that `abstractstaticmethod` is deprecated, and `staticmethod` does not induce a type error – Joey Baruch Jul 22 '21 at 16:49
  • 4
    Thanks for showing the new feature. – Charlie 木匠 Nov 08 '21 at 01:45
  • 1
    @JoeyBaruch As written in the documentation of the `abc` package (see https://docs.python.org/3/library/abc.html#abc.abstractmethod), you can combine `@staticmethod` with `@abstractmethod` to get the desired effect (the decorator `@abstractmethod` should be placed at the innermost level). – Lightspark Mar 29 '22 at 14:18
  • This is the best answer if you don't want the child classes to have to explicitly implement a base class. https://stackoverflow.com/a/66977467/733092 makes a good short introduction to Protocols for anyone who skimmed over this. – Noumenon Oct 18 '22 at 01:10
  • I'm inclined to argue that child classes _should_ implement the new class for readability and maintainability. If the use of the function declared in the protocol and used as a parameter in another function (as in this example code) is wrapped in a `try` block that catches all exceptions of any type (an unfortunately common occurrence in some of the codebases I've seen), you may have a bug on your hands that's extremely difficult to isolate. – Bill Horvath Jul 28 '23 at 16:24
65

interface supports Python 2.7 and Python 3.4+.

To install interface you have to

pip install python-interface

Example Code:

from interface import implements, Interface

class MyInterface(Interface):

    def method1(self, x):
        pass

    def method2(self, x, y):
        pass


class MyClass(implements(MyInterface)):

    def method1(self, x):
        return x * 2

    def method2(self, x, y):
        return x + y
Ahmad Ismail
  • 11,636
  • 6
  • 52
  • 87
  • 21
    A major advantage of this library, IMHO, is the early failure it gives you: If your class does not correctly implement a specified interface, you get an exception as soon as the class is read in - you don't even have to use it. With Python's own abstract base class, you get the exception when you first instantiate your class, which could be much later. – Hans Apr 10 '19 at 05:51
  • 4
    It's unnecessary, ABC offers a similar, built-in functionality. – Daniel Jan 09 '20 at 23:11
  • 2
    @DanielCasares does ABC offer an actual interface or do you mean that abstract classes without state or implementations are the solution that ABC offers? – asaf92 Mar 06 '20 at 13:23
  • python is so terrible that it doesnt know this at compile time. its so backward and un-safe for a modern language. its the opposite of progress actually. – Luke Jul 23 '23 at 05:11
46

There are third-party implementations of interfaces for Python (most popular is Zope's, also used in Twisted), but more commonly Python coders prefer to use the richer concept known as an "Abstract Base Class" (ABC), which combines an interface with the possibility of having some implementation aspects there too. ABCs are particularly well supported in Python 2.6 and later, see the PEP, but even in earlier versions of Python they're normally seen as "the way to go" -- just define a class some of whose methods raise NotImplementedError so that subclasses will be on notice that they'd better override those methods!-)

Community
  • 1
  • 1
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 4
    *There are third-party implementations of interfaces for Python* What does it mean? Could you please explain ABC ? – Pratik Deoghare Jan 23 '10 at 18:42
  • 3
    Well, I'll take issue with ABC's being "richer". ;) There are things zope.interface can do that ABC's can't as well as the other way around. But otherwise you are as usual right. +1 – Lennart Regebro Jan 23 '10 at 19:26
  • 1
    @Alfred: It means that modules like zope.interface is not included in the standard library, but available from pypi. – Lennart Regebro Jan 23 '10 at 19:27
  • I have still hard time to grok the concept of ABC's. Would it be possible for somebody to rewrite https://twistedmatrix.com/documents/current/core/howto/components.html (IMHO, an excellent explanation of the interfaces concept) in terms of ABC's. Does it make a sense? – mcepl Jul 29 '16 at 08:25
25

Something like this (might not work as I don't have Python around):

class IInterface:
    def show(self): raise NotImplementedError

class MyClass(IInterface):
    def show(self): print "Hello World!"
Bandi-T
  • 3,231
  • 1
  • 20
  • 15
  • 4
    What should I do about `__init__(self)` the constructor? – Pratik Deoghare Jan 23 '10 at 18:39
  • 1
    Up to you. Since there is no compile-time check against constructing an object from an abstract class you would not gain any protection during coding/compiling. There will be a constructor inherited, so the object *would* get created, just be "empty". It is up to you to decide whether you'd be better off by allowing this to happen and catch failures later, or explicitly stop the program right then and there by implementing a similar constructor throwing an exception. – Bandi-T Jan 23 '10 at 18:45
  • 2
    That's why `abc.ABC` is much better than raising `NotImplementedError` - instantiation of an `abc.ABC` subclass that does not implement all the abstract methods fails early, so you are protected against errors. See my answer below for how the error looks like. – mrts Jul 13 '18 at 09:13
14

My understanding is that interfaces are not that necessary in dynamic languages like Python. In Java (or C++ with its abstract base class) interfaces are means for ensuring that e.g. you're passing the right parameter, able to perform set of tasks.

E.g. if you have observer and observable, observable is interested in subscribing objects that supports IObserver interface, which in turn has notify action. This is checked at compile time.

In Python, there is no such thing as compile time and method lookups are performed at runtime. Moreover, one can override lookup with __getattr__() or __getattribute__() magic methods. In other words, you can pass, as observer, any object that can return callable on accessing notify attribute.

This leads me to the conclusion, that interfaces in Python do exist - it's just their enforcement is postponed to the moment in which they are actually used

Tomasz Zieliński
  • 16,136
  • 7
  • 59
  • 83