Diferencia entre clase abstracta e interfaz en Python

¿Cuál es la diferencia entre la clase abstracta y la interfaz en Python?

Lo que verás a veces es lo siguiente:

class Abstract1( object ): """Some description that tells you it's abstract, often listing the methods you're expected to supply.""" def aMethod( self ): raise NotImplementedError( "Should have implemented this" ) 

Debido a que Python no tiene (y no necesita) un contrato formal de Interfaz, la distinción de estilo Java entre abstracción e interfaz no existe. Si alguien se esfuerza por definir una interfaz formal, también será una clase abstracta. Las únicas diferencias estarían en la intención declarada en el docstring.

Y la diferencia entre el resumen y la interfaz es una cuestión de peinado cuando tienes que escribir pato.

Java usa interfaces porque no tiene herencia múltiple.

Como Python tiene herencia múltiple, también puedes ver algo como esto.

 class SomeAbstraction( object ): pass # lots of stuff - but missing something class Mixin1( object ): def something( self ): pass # one implementation class Mixin2( object ): def something( self ): pass # another class Concrete1( SomeAbstraction, Mixin1 ): pass class Concrete2( SomeAbstraction, Mixin2 ): pass 

Esto utiliza una clase de superclase abstracta con mixins para crear subclases concretas que están separadas.

¿Cuál es la diferencia entre la clase abstracta y la interfaz en Python?

Una interfaz, para un objeto, es un conjunto de métodos y atributos en ese objeto.

En Python, podemos usar una clase base abstracta para definir y aplicar una interfaz.

Usando una clase base abstracta

Por ejemplo, digamos que queremos usar una de las clases base abstractas del módulo de collections :

 import collections class MySet(collections.Set): pass 

Si intentamos usarlo, obtenemos un TypeError porque la clase que creamos no admite el comportamiento esperado de los conjuntos:

 >>> MySet() Traceback (most recent call last): File "", line 1, in  TypeError: Can't instantiate abstract class MySet with abstract methods __contains__, __iter__, __len__ 

Por lo tanto, debemos implementar al menos __contains__ , __iter__ y __len__ . Usemos este ejemplo de implementación de la documentación :

 class ListBasedSet(collections.Set): """Alternate set implementation favoring space over speed and not requiring the set elements to be hashable. """ def __init__(self, iterable): self.elements = lst = [] for value in iterable: if value not in lst: lst.append(value) def __iter__(self): return iter(self.elements) def __contains__(self, value): return value in self.elements def __len__(self): return len(self.elements) s1 = ListBasedSet('abcdef') s2 = ListBasedSet('defghi') overlap = s1 & s2 

Implementación: Creación de una clase base abstracta

Podemos crear nuestra propia Clase Base Abstracta estableciendo la metaclase en abc.ABCMeta y usando el decorador de métodos abc.abstractmethod en métodos relevantes. La metaclase agregará las funciones decoradas al atributo __abstractmethods__ , evitando la __abstractmethods__ instancias hasta que se definan.

 import abc 

Por ejemplo, “effable” se define como algo que se puede express en palabras. Digamos que queríamos definir una clase base abstracta que sea effable, en Python 2:

 class Effable(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def __str__(self): raise NotImplementedError('users must define __str__ to use this base class') 

O en Python 3, con el ligero cambio en la statement de metaclase:

 class Effable(object, metaclass=abc.ABCMeta): @abc.abstractmethod def __str__(self): raise NotImplementedError('users must define __str__ to use this base class') 

Ahora, si intentamos crear un objeto effable sin implementar la interfaz:

 class MyEffable(Effable): pass 

y tratar de instanciarlo:

 >>> MyEffable() Traceback (most recent call last): File "", line 1, in  TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__ 

Nos dicen que no hemos terminado el trabajo.

Ahora si cumplimos proporcionando la interfaz esperada:

 class MyEffable(Effable): def __str__(self): return 'expressable!' 

Entonces podemos usar la versión concreta de la clase derivada del resumen:

 >>> me = MyEffable() >>> print(me) expressable! 

Hay otras cosas que podríamos hacer con esto, como registrar subclases virtuales que ya implementan estas interfaces, pero creo que eso está fuera del scope de esta pregunta. Sin embargo, los otros métodos demostrados aquí tendrían que adaptar este método utilizando el módulo abc para hacerlo.

Conclusión

Hemos demostrado que la creación de una clase base abstracta define interfaces para objetos personalizados en Python.

Python> = 2.6 tiene clases base abstractas .

Las clases base abstractas (ABCs abreviadas) complementan la tipificación duck al proporcionar una manera de definir interfaces cuando otras técnicas como hasattr () serían torpes. Python viene con muchos ABCs incorporados para estructuras de datos (en el módulo de colecciones), números (en el módulo de números) y flujos (en el módulo io). Puedes crear tu propio ABC con el módulo abc.

También está el módulo de Interfaz Zope , que es utilizado por proyectos fuera de zope, como retorcido. No estoy realmente familiarizado con esto, pero hay una página wiki aquí que podría ayudar.

En general, no necesita el concepto de clases abstractas, o interfaces en python (editado – vea la respuesta de S.Lott para más detalles).

Python realmente no tiene ninguno de los dos conceptos.

Utiliza la escritura de pato, que elimina la necesidad de interfaces (al menos para la computadora :-))

Python <= 2.5: las clases base obviamente existen, pero no hay una forma explícita de marcar un método como 'virtual puro', por lo que la clase no es realmente abstracta.

Python> = 2.6: Existen clases base abstractas ( http://docs.python.org/library/abc.html ). Y le permite especificar métodos que deben implementarse en subclases. No me gusta mucho la syntax, pero la característica está ahí. En la mayoría de los casos, probablemente sea mejor usar la escritura de pato desde el lado del cliente que utiliza.

En una forma más básica de explicar: una interfaz es algo así como una bandeja para muffins vacía. Es un archivo de clase con un conjunto de definiciones de métodos que no tienen código.

Una clase abstracta es lo mismo, pero no todas las funciones deben estar vacías. Algunos pueden tener código. No es estrictamente vacío.

Por qué diferenciar: no hay mucha diferencia práctica en Python, pero en el nivel de planificación para un proyecto grande, podría ser más común hablar de interfaces, ya que no hay código. Especialmente si estás trabajando con progtwigdores de Java que están acostumbrados al término.

En general, las interfaces se usan solo en idiomas que usan el modelo de clase de herencia simple. En estos lenguajes de herencia única, las interfaces se usan normalmente si alguna clase puede usar un método o conjunto de métodos en particular. También en estos lenguajes de herencia única, las clases abstractas se usan para tener variables de clase definidas además de ninguno o más métodos, o para explotar el modelo de herencia única para limitar el rango de clases que podrían usar un conjunto de métodos.

Los idiomas que admiten el modelo de herencia múltiple tienden a usar solo clases o clases base abstractas y no interfaces. Como Python admite herencia múltiple, no usa interfaces y querría usar clases base o clases base abstractas.

http://docs.python.org/library/abc.html