Comment implémenter des interfaces en python?

public interface IInterface
{
    void show();
}

 public class MyClass : IInterface
{

    #region IInterface Members

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

    #endregion
}

Comment implémenter l'équivalent Python de ce code C#?

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!'

Est-ce une bonne idée?? Veuillez donner des exemples dans vos réponses.

78
demandé sur Byte Commander 2010-01-23 21:29:07

6 réponses

Comme mentionné par d'autres ici:

Les Interfaces ne sont pas nécessaires en Python. C'est parce que Python a un héritage multiple approprié, et aussi ducktyping, ce qui signifie que les endroits où vous devez avoir des interfaces en Java, vous n'avez pas besoin de les avoir en Python.

Cela dit, il y a encore plusieurs utilisations pour les interfaces. Certains d'entre eux sont couverts par des Classes de base abstraites Pythons, introduites dans Python 2.6. Ils sont utiles, si vous voulez faire des classes de base qui ne peuvent pas être instancié, mais fournit une interface spécifique ou une partie d'une implémentation.

Une autre utilisation est si vous voulez en quelque sorte spécifier qu'un objet implémente une interface spécifique, et vous pouvez utiliser ABC pour cela aussi en sous-classant à partir d'eux. Une autre façon est zope.interface, un module qui fait partie de L'Architecture des composants Zope, un framework de composants vraiment génial. Ici, vous ne sous-classez pas les interfaces, mais marquez plutôt les classes (ou même les instances) comme implémentant un interface. Cela peut également être utilisé pour rechercher des composants à partir d'un composant de registre. Supercool!

78
répondu Lennart Regebro 2017-11-17 13:49:41

L'Utilisation du module abc pour les classes de base abstraites semble faire l'affaire.

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()
30
répondu Peter Torpman 2014-04-17 13:11:36

Il existe des implémentations tierces d'interfaces pour Python (le plus populaire est de Zope, également utilisé dans Twisted), mais plus généralement les codeurs Python préfèrent utiliser le concept plus riche connu sous le nom de "classe de Base abstraite" (ABC), qui combine une interface avec la possibilité d'avoir certains aspects d'implémentation là aussi. Les abc sont particulièrement bien pris en charge dans Python 2.6 et versions ultérieures, voir le PEP , mais même dans les versions antérieures de Python, ils sont normalement considérés comme " le way to go " - il suffit de définir une classe dont certaines méthodes soulèvent NotImplementedError afin que les sous-classes soient à l'avis qu'elles feraient mieux de remplacer ces méthodes!-)

21
répondu Alex Martelli 2010-01-23 18:33:56

Quelque chose comme ça (pourrait ne pas fonctionner car je n'ai pas Python autour):

class IInterface:
    def show(self): raise NotImplementedError

class MyClass(IInterface):
    def show(self): print "Hello World!"
13
répondu Bandi-T 2010-01-23 18:36:23

Ma compréhension est que les interfaces ne sont pas si nécessaires dans les langages dynamiques comme Python. En Java (ou C++ avec sa classe de base abstraite), les interfaces sont des moyens pour s'assurer que, par exemple, vous passez le bon paramètre, capable d'effectuer un ensemble de tâches.

Par exemple, si vous avez observer et observable, observable est intéressé par l'abonnement aux objets qui prennent en charge l'interface IObserver, qui à son tour a notify action. Ceci est vérifié au moment de la compilation.

En Python, il n'y en a pas chose comme compile time et les recherches de méthode sont effectuées au moment de l'exécution. De plus, on peut remplacer la recherche avec les méthodes magiques __getattr__() ou __getattribute__ (). En d'autres termes, vous pouvez passer, en tant qu'observateur, n'importe quel objet pouvant renvoyer callable lors de l'accès à l'attribut notify.

Cela m'amène à la conclusion, que les interfaces en Python existent - c'est juste que leur application est reportée au moment où elles sont réellement utilisées

6
répondu Tomasz Zielinski 2010-01-23 19:19:41

L'implémentation d'interfaces avec des classes de base abstraites est beaucoup plus simple dans Python 3 moderne et elles servent de contrat d'interface pour les extensions de plug-in.

Créer l'interface/classe de base abstraite:

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)

Crée une sous-classe normale et remplace toutes les méthodes abstraites:

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)

Vous pouvez éventuellement avoir une implémentation commune dans les méthodes abstraites comme dans create_sale_invoice(), en l'appelant explicitement avec super() dans la sous-classe comme ci-dessus.

Instanciation d'un la sous-classe qui n'implémente pas toutes les méthodes abstraites échoue:

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

Vous pouvez également avoir des propriétés abstraites, des méthodes statiques et de classe en combinant les annotations correspondantes avec @abstractmethod.

Les classes de base abstraites sont idéales pour implémenter des systèmes basés sur des plugins. Toutes les sous-classes importées d'une classe sont accessibles via __subclasses__(), donc si vous chargez toutes les classes à partir d'un répertoire de plugin avec importlib.import_module() et si elles sous-classe la classe de base, vous avez un accès direct à eux via __subclasses__() et vous pouvez assurez-vous que le contrat d'interface est appliqué pour tous lors de l'instanciation.

Voici l'implémentation de chargement du plugin pour l'exemple AccountingSystem ci-dessus:

...
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

Ensuite, vous pouvez accéder à l'objet plugin système de comptabilité via la classe AccountingSystem:

>>> accountingsystem = AccountingSystem.instance()

(inspiré par ce poste PyMOTW-3 .)

1
répondu mrts 2018-07-14 12:23:42