web-dev-qa-db-fra.com

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 Python équivalent 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?? S'il vous plaît donner des exemples dans vos réponses.

129
Pratik Deoghare

Comme mentionné par d'autres ici:

Les interfaces ne sont pas nécessaires en Python. Ceci est dû au fait que Python possède un héritage multiple correct, ainsi que ducktyping, ce qui signifie que les endroits où vous devez ont 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. Certaines d'entre elles sont couvertes par les classes de base abstraites Pythons, introduites dans Python 2.6. Ils sont utiles si vous voulez créer des classes de base qui ne peuvent pas être instanciées, mais fournissent une interface spécifique ou une partie d’une implémentation.

Une autre utilisation consiste à spécifier si un objet doit implémenter une interface spécifique. Vous pouvez également utiliser ABC pour cela en sous-classant ces interfaces. Zope.interface est un autre moyen de faire partie de l'architecture de composants de Zope, un framework de composants vraiment génial. Ici, vous ne sous-classez pas les interfaces, mais vous marquez les classes (ou même les instances) comme implémentant une interface. Cela peut également être utilisé pour rechercher des composants dans un registre de composants. Super cool!

113
Lennart Regebro

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()
53
Peter Torpman

Il existe des implémentations tierces d'interfaces pour Python (le plus populaire est Zope's , également utilisé dans Twisted ), mais plus communément Python _ Les codeurs préfèrent utiliser le concept plus riche appelé "classe de base abstraite" (ABC), qui associe une interface à la possibilité de présenter également certains aspects de la mise en oeuvre. Les ABC sont particulièrement bien supportés dans Python 2.6 et versions ultérieures, voir le PEP , mais même dans les versions antérieures de Python, ils sont normalement vus comme "le chemin to go "- définissez simplement une classe dont certaines méthodes soulèvent NotImplementedError afin que les sous-classes soient averties qu'elles feraient mieux de remplacer ces méthodes! -)

26
Alex Martelli

interface supporte Python 2.7 et Python 3.4+.

Pour installer l'interface, vous devez

pip install python-interface

Exemple de 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
19
blueray

Quelque chose comme ceci (peut 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!"
18
Bandi-T

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

Créez la classe de base interface/abstract:

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éez une sous-classe normale et remplacez 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.

L'instanciation d'une 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 des méthodes de classe en combinant les annotations correspondantes avec @abstractmethod.

Les classes de base abstraites sont idéales pour l'implémentation de systèmes à base de plug-in. Toutes les sous-classes importées d'une classe sont accessibles via __subclasses__(). Par conséquent, si vous chargez toutes les classes d'un répertoire de plug-ins avec importlib.import_module() et si elles sous-classent la classe de base, vous pouvez y accéder directement via __subclasses__() et vous pouvez être sûr que le contrat d'interface est appliqué. pour tous pendant 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

Vous pouvez ensuite accéder à l’objet plug-in de système de comptabilité via la classe AccountingSystem:

>>> accountingsystem = AccountingSystem.instance()

(Inspiré par cet article de PyMOTW- .)

15
mrts

D'après ce que je comprends, les interfaces ne sont pas nécessaires dans des langages dynamiques comme Python. Dans Java (ou C++ avec sa classe de base abstraite), les interfaces permettent de s'assurer que, par exemple, vous passez le bon paramètre, capable d'effectuer un ensemble de tâches.

Par exemple. si vous avez observable et observable, observable est intéressé par la souscription d’objets prenant en charge l’interface IObserver, qui a à son tour une action notify. Ceci est vérifié lors de la compilation.

En Python, compile time n'existe pas, et les recherches de méthode sont effectuées à l'exécution. De plus, vous pouvez remplacer la recherche par les méthodes magiques __getattr __ () ou __getattribute __ (). En d'autres termes, vous pouvez transmettre, en tant qu'observateur, tout objet pouvant retourner appelable en accédant à l'attribut notify.

Ceci m’amène à la conclusion que les interfaces dans Python existent - leur application est simplement reportée au moment où elles sont réellement utilisées

7
Tomasz Zieliński