Saltar al contenido

Diferencia entre clase abstracta e interfaz en Python

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

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *