Pregunta ¿Cómo implemento interfaces en python?


public interface IInterface
{
    void show();
}

 public class MyClass : IInterface
{

    #region IInterface Members

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

    #endregion
}

¿Cómo implemento el equivalente Python de este código 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!'

¿¿Es esta una buena idea?? Por favor da ejemplos en tus respuestas.


75
2018-01-23 18:29


origen


Respuestas:


Como se menciona por otros aquí:

Las interfaces no son necesarias en Python. Esto se debe a que Python tiene una herencia múltiple adecuada, y también ducktyping, lo que significa que los lugares donde debe tener interfaces en Java, no es necesario tenerlas en Python.

Dicho esto, todavía hay varios usos para las interfaces. Algunos de ellos están cubiertos por Pythons Abstract Base Classes, presentado en Python 2.6. Son útiles, si desea crear clases base que no se puedan crear instancias, pero que proporcionen una interfaz específica o parte de una implementación.

Otro uso es si de alguna manera desea especificar que un objeto implementa una interfaz específica, y puede usar ABC para eso también subclases de ellos. Otra forma es zope.interface, un módulo que forma parte de la Zope Component Architecture, un marco de componentes realmente asombroso. Aquí no hace una subclase de las interfaces, sino que marca las clases (o incluso las instancias) como implementando una interfaz. Esto también se puede usar para buscar componentes de un registro de componentes. ¡Super guay!


71
2018-01-23 19:35



Usar el módulo abc para clases base abstractas parece ser el truco.

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()

25
2018-04-17 13:11



Existen implementaciones de interfaces de terceros para Python (la más popular es Zope, también utilizado en Retorcido), pero más comúnmente los codificadores de Python prefieren usar el concepto más rico conocido como "Clase base abstracta" (ABC), que combina una interfaz con la posibilidad de tener algunos aspectos de implementación allí también. Los ABC están especialmente bien soportados en Python 2.6 y posterior, ver el PEP, pero incluso en las versiones anteriores de Python normalmente se ven como "el camino a seguir", simplemente define una clase que algunos de sus métodos plantean NotImplementedError ¡para que las subclases tengan en cuenta que es mejor anular esos métodos! -)


19
2018-01-23 18:33



Algo así (podría no funcionar ya que no tengo Python):

class IInterface:
    def show(self): raise NotImplementedError

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

13
2018-01-23 18:36



Mi entendimiento es que las interfaces no son tan necesarias en lenguajes dinámicos como Python. En Java (o C ++ con su clase base abstracta), las interfaces son medios para garantizar que, p. estás pasando el parámetro correcto, capaz de realizar un conjunto de tareas.

P.ej. si tiene observador y observable, observable está interesado en suscribir objetos que soporte la interfaz IObserver, que a su vez tiene notify acción. Esto se verifica en tiempo de compilación.

En Python, no existe tal cosa compile time y las búsquedas de métodos se realizan en tiempo de ejecución. Además, uno puede anular la búsqueda con __getattr __ () o __getattribute __ () métodos mágicos. En otras palabras, puede pasar, como observador, cualquier objeto que pueda devolver el acceso invocable notify atributo.

Esto me lleva a la conclusión de que las interfaces en Python existe - Es solo que su aplicación se pospone al momento en que se usan realmente


6
2018-01-23 19:19



La implementación de interfaces con clases base abstractas es mucho más simple en Python 3 moderno y cumplen un propósito como un contrato de interfaz para extensiones de plug-in.

Cree la clase base de la interfaz / resumen:

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)

Cree una subclase normal y anule todos los métodos abstractos:

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)

Opcionalmente, puede tener una implementación común en los métodos abstractos como en create_sale_invoice()llamándolo con super() explícitamente en la subclase como arriba.

La creación de una subclase que no implementa todos los métodos abstractos falla:

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

También puede tener propiedades abstractas, métodos estáticos y de clase combinando las anotaciones correspondientes con @abstractmethod.

Las clases base abstractas son excelentes para implementar sistemas basados ​​en complementos. Se puede acceder a todas las subclases importadas de una clase a través de __subclasses__(), así que si cargas todas las clases de un directorio de complementos con importlib.import_module() y si subclasifican la clase base, tienes acceso directo a ellos a través de __subclasses__() y puede estar seguro de que el contrato de interfaz se aplica para todos ellos durante la creación de instancias.

Aquí está la implementación de carga del complemento para el AccountingSystem ejemplo de arriba:

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

Luego puede acceder al objeto de complemento del sistema de contabilidad a través del AccountingSystem clase:

>>> accountingsystem = AccountingSystem.instance()

(Inspirado por esta publicación de PyMOTW-3.)


0
2017-07-10 20:06