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!
Answer from Lennart Regebro on Stack OverflowAs 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!
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.)
Classes and Implementing Interfaces
Native Interface Support in Python - Ideas - Discussions on Python.org
How do I implement interfaces in python?
How to implement interfaces in Python effectively? - TestMu AI Community
Videos
I having trouble moving on from lesson past Interfaces. I understand the proposed purpose. An interface allows for abstraction so that my code can have loosely coupled classes and methods.
What I don't understand is how that actually works. Can anyone recommend a good clear write up or YouTube. Everything I find seems to confuse me further.
Please and thank you.
Using Python's multiple inheritance (MI) for interfaces, abstract base classes, mixins, or similar techniques is perfectly fine. In most cases, the MRO produces intuitive results.
However, object initialization under multiple inheritance is really tricky. In Python you cannot combine multiple classes per MI unless all participating classes have been designed for MI. The issue is that the __init__() method cannot know from which class it will be called and what the signature of the super().__init__() method will be. Effectively, this means that MI constructors:
- must call the
super().__init__() - must only take arguments by name, not by position
- must forward any
**kwargsto thesuper().__init__() - must not warn on unexpected arguments
Where possible, the better alternative is to avoid __init__() methods for interface-like classes, and instead express requirements through abstract methods. For example, instead of a BananaContainer class, we might write this interface/ABC:
import abc # abstract base class
class BananaContainer(abc.ABC):
@property
@abc.abstractmethod
def bananas(self) -> list:
raise NotImplementedError
If a class wants to be a BananaContainer, it would have to implement that property.
In general, it is perfectly alright if you have a class that inherits from multiple interfaces or mixins. Aside from name collisions, the above __init__() problems, and general API bloat of the class, no noteworthy issues arise.
The second part of your question proposes a capability-based approach instead of using inheritance. Using composition instead of inheritance is often a very very good idea. For example, you eliminate the initialization problems by design. It also tends to lead to more explicit APIs that are easier to navigate and avoid name clashes. There should be some method that either returns an object representing a capability, or None if the capability isn't supported.
But these capabilities can be implemented in different ways: either by using normal composition, or by storing the capabilities in your own data structures.
Unless you have special needs for the object model, stick to the language. Store methods in normal object fields, provide normal methods to access them. This leads to a more comfortable API, and is more likely to support auto-completer and type-checkers.
If you need to modify the available capabilities of an object at run-time, and need to introduce new kinds of capabilities at run-time, then using a dictionary may be appropriate. But at this point you are inventing your own object system. This may be a good idea e.g. in games that have complex capability systems where new capabilities shall be defined in configuration files.
Most software does not have these requirements, and does not benefit from that kind of flexibility.
Additionally, Python's built-in object system is flexible enough that you could create new types and new methods without having to create a new object system. Builtins like
getattr(),setattr(),hasattr(), and thetype()constructor come in handy here.
I would likely express an object that can have both AppleContainer and BananaContainer capabilities like this:
class BananaContainer:
...
class AppleContainer:
...
class HasCapabilities:
def __init__(self, x, y, z):
# somehow determine the appropriate capabilities and initialize them
self._banana_container = BananaContainer(y) if x else None
self._apple_container = AppleContainer(y)
@property
def as_banana_container(self) -> Optional[BananaContainer]:
return self._banana_container
@property
def as_apple_container(self) -> Optional[AppleContainer]:
return self._apple_container
o = HasCapabilities(...)
bc = o.as_banana_container
if bc is not None:
bc.do_banana_things()
Or with Python 3.8 assignment expressions:
if (bc := o.as_banana_container) is not None:
bc.do_banana_things()
If you want to have some custom mechanisms for reflection over capabilities, you can implement that on top of this solution, with some amount of boilerplate. If we want to be MI-safe, we might declare the following base class that all capability-having classes need to inherit:
class CapabilityReflection:
# a base implementations so that actual implementations
# can safely call super()._get_capabilities()
def _list_capabilities(self):
return ()
def all_capabilities(self):
"""deduplicated set of capabilities that this object supports."""
set(self._list_capabilities())
def get_capability(self, captype):
"""find a capability by its type. Returns None if not supported."""
return None
which in the above case would have been implemented as:
class HasCapabilities(CapabilityReflection):
...
def _list_capabilities(self):
caps = [ # go through properties in case they have been overridden
self.as_banana_container,
self.as_apple_container,
]
yield from (cap for cap in caps if cap is not None)
yield from super()._list_capabilities()
def get_capability(self, captype):
if captype == BananaContainer:
return self.as_banana_container
if captype == AppleContainer:
return self.as_apple_container
return super().get_capability(captype)
In order to ensure a class has some properties, I make base "interface" classes
While this is a common design pattern in statically typed languages, Python programmers consider more idiomatic to use duck typing for your classes. Since the language is dynamically typed, if you have Foo and Bar classes that both can contain bananas, you are free to call unknown.banana on a variable that can be either. If unknown can be an object that don't implement banana, you can also use getattr or try/except AttributeError blocks. The explicit interface is just bloat over features the language already support.
If for any reason you don't want to get rid of these interfaces, then you could at least use multiple inheritance. It exists because it has uses and is correct to use in many cases.
can it hit us back later with problems like method resolution order or name collisions ?
In your multiple inheritance declaration, the first object has priority when it comes to symbol collisions. In some cases, it's a feature, but you have to be careful this doesn't cause unintended overrides, like you would when defining methods and properties in a child class.
The capability suggestion is overly defensive over inheritance mechanisms. Making sure you don't accidentally override is your responsibility, but it shouldn't be a huge burden. If it happens to be one, it's likely you have other problems. And in cases you are not sure of the symbols contained in a class and want to use it as a black box, it may be appropriate to favor composition.