Solución:
Lo que verá 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 de interfaz formal, 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 la cadena de documentos.
Y la diferencia entre abstracto e interfaz es algo escalofriante cuando se escribe pato.
Java usa interfaces porque no tiene herencia múltiple.
Debido a que Python tiene herencia múltiple, también puede 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 usa una especie de superclase abstracta con mixins para crear subclases concretas que son disjuntas.
¿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 hacer cumplir una interfaz.
Usar una clase base abstracta
Por ejemplo, digamos que queremos usar una de las clases base abstractas del collections
módulo:
import collections
class MySet(collections.Set):
pass
Si intentamos usarlo, obtenemos un TypeError
porque la clase que creamos no admite el comportamiento esperado de conjuntos:
>>> MySet()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MySet with abstract methods
__contains__, __iter__, __len__
Por lo que estamos obligados a implementar en 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 configurando la metaclase en abc.ABCMeta
y usando el abc.abstractmethod
decorador sobre métodos relevantes. La metaclase agregará las funciones decoradas a la __abstractmethods__
atributo, evitando la creación de instancias hasta que se definan.
import abc
Por ejemplo, “effable” se define como algo que se puede expresar con palabras. Digamos que queremos definir una clase base abstracta que sea borrable, 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 declaración de la 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 borrable sin implementar la interfaz:
class MyEffable(Effable):
pass
e intentar instanciarlo:
>>> MyEffable()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__
Se nos dice que no hemos terminado el trabajo.
Ahora bien, 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 de la abstracta:
>>> 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á más allá del alcance de esta pregunta. Los otros métodos demostrados aquí tendrían que adaptar este método utilizando el abc
módulo para hacerlo, sin embargo.
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 (ABC abreviado) complementan la escritura de pato proporcionando una forma de definir interfaces cuando otras técnicas como hasattr () serían torpes. Python viene con muchos ABC 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). Puede crear su propio ABC con el módulo abc.
También está el módulo Zope Interface, que es utilizado por proyectos fuera de zope, como twisted. No estoy familiarizado con él, 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; consulte la respuesta de S.Lott para obtener más detalles).