Quelle est la différence entre abstract class et interface en Python?
Ce que vous verrez parfois est le suivant:
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" )
Comme Python n'a pas (et n'a pas besoin) de contrat d'interface formel, la distinction de style Java entre abstraction et interface n'existe pas. Si quelqu'un s'efforce de définir une interface formelle, ce sera également une classe abstraite. Les seules différences seraient dans l'intention déclarée dans la docstring.
Et la différence entre abstrait et interface est une chose difficile quand vous avez la frappe du canard.
Java utilise des interfaces car il ne possède pas d'héritage multiple.
Parce que Python a un héritage multiple, vous pouvez également voir quelque chose comme ceci
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
Cela utilise une sorte de super-classe abstraite avec mixins pour créer des sous-classes concrètes disjointes.
Quelle est la différence entre abstract class et interface en Python?
Une interface, pour un objet, est un ensemble de méthodes et d'attributs sur cet objet.
En Python, nous pouvons utiliser une classe de base abstraite pour définir et appliquer une interface.
Par exemple, supposons que nous voulions utiliser l’une des classes de base abstraites du module collections
:
import collections
class MySet(collections.Set):
pass
Si nous essayons de l'utiliser, nous obtenons un TypeError
car la classe que nous avons créée ne prend pas en charge le comportement attendu des ensembles:
>>> 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__
Nous devons donc mettre en œuvre au moins __contains__
, __iter__
et __len__
. Utilisons cet exemple d'implémentation à partir de documentation :
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
Nous pouvons créer notre propre classe de base abstraite en définissant la métaclasse sur abc.ABCMeta
et en utilisant le décorateur abc.abstractmethod
sur des méthodes appropriées. La métaclasse ajoutera les fonctions décorées à l'attribut __abstractmethods__
, empêchant l'instanciation jusqu'à ce que celles-ci soient définies.
import abc
Par exemple, "effable" est défini comme quelque chose qui peut être exprimé avec des mots. Supposons que nous voulions définir une classe de base abstraite qui soit 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')
Ou dans Python 3, avec le léger changement dans la déclaration de métaclasse:
class Effable(object, metaclass=abc.ABCMeta):
@abc.abstractmethod
def __str__(self):
raise NotImplementedError('users must define __str__ to use this base class')
Maintenant, si nous essayons de créer un objet effable sans implémenter l'interface:
class MyEffable(Effable):
pass
et essayez de l'instancier:
>>> MyEffable()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__
On nous dit que nous n'avons pas fini le travail.
Maintenant, si nous nous conformons en fournissant l'interface attendue:
class MyEffable(Effable):
def __str__(self):
return 'expressable!'
nous pouvons alors utiliser la version concrète de la classe dérivée de la classe abstraite:
>>> me = MyEffable()
>>> print(me)
expressable!
Nous pourrions faire autre chose avec cela, comme enregistrer des sous-classes virtuelles qui implémentent déjà ces interfaces, mais je pense que cela dépasse le cadre de cette question. Les autres méthodes présentées ici devront toutefois adapter cette méthode à l'aide du module abc
.
Nous avons démontré que la création d'une classe de base abstraite définit des interfaces pour des objets personnalisés en Python.
Python> = 2.6 a classes de base abstraites .
Les classes de base abstraites (ABC abrégées) complètent le typage de canard en fournissant un moyen de définir des interfaces lorsque d’autres techniques telles que hasattr () seraient maladroites. Python est livré avec de nombreux ABC intégrés pour les structures de données (dans le module collections), les nombres (dans le module numbers) et les flux (dans le module io). Vous pouvez créer votre propre ABC avec le module abc.
Il y a aussi le module Zope Interface , qui est utilisé par les projets en dehors de zope, comme twisted. Je ne le connais pas vraiment, mais il y a une page wiki ici qui pourrait aider.
En général, vous n'avez pas besoin du concept de classes abstraites ni d'interfaces dans python (modifié - voir la réponse de S.Lott pour plus de détails).
Python n'a pas vraiment l'un ou l'autre concept.
Il utilise la frappe de canard, ce qui supprime le besoin d'interfaces (au moins pour l'ordinateur :-))
Python <= 2.5: les classes de base existent évidemment, mais il n'y a pas de moyen explicite de marquer une méthode comme 'pure virtual', donc la classe n'est pas vraiment abstraite.
Python> = 2.6: les classes de base abstraites font existe ( http://docs.python.org/library/abc.html ). Et vous permettent de spécifier les méthodes qui doivent être implémentées dans des sous-classes. Je n'aime pas beaucoup la syntaxe, mais la fonctionnalité est là. La plupart du temps, il est probablement préférable d'utiliser la saisie à l'aide de canards du côté client "utilisant".
Pour expliquer plus simplement: une interface est un peu comme un moule à muffins vide. C'est un fichier de classe avec un ensemble de définitions de méthodes sans code.
Une classe abstraite est la même chose, mais toutes les fonctions ne doivent pas nécessairement être vides. Certains peuvent avoir du code. Ce n'est pas strictement vide.
Pourquoi différencier: Il n’ya pas beaucoup de différence pratique en Python, mais au niveau de la planification d’un grand projet, il pourrait être plus courant de parler d’interfaces, car il n’ya pas de code. Surtout si vous travaillez avec Java programmeurs habitués au terme.
En général, les interfaces ne sont utilisées que dans les langages utilisant le modèle de classe à héritage unique. Dans ces langages à héritage unique, les interfaces sont généralement utilisées si une classe peut utiliser une méthode ou un ensemble de méthodes particulier. De plus, dans ces langages à héritage unique, les classes abstraites sont utilisées pour définir des variables de classe définies en plus d’aucune ou plusieurs méthodes, ou pour exploiter le modèle à héritage unique afin de limiter la plage de classes pouvant utiliser un ensemble de méthodes.
Les langues prenant en charge le modèle à héritages multiples ont tendance à utiliser uniquement des classes ou des classes de base abstraites et non des interfaces. Étant donné que Python prend en charge l'héritage multiple, il n'utilise pas d'interface et vous souhaitez utiliser des classes de base ou des classes de base abstraites.
Les classes abstraites sont des classes qui contiennent une ou plusieurs méthodes abstraites. Outre les méthodes abstraites, les classes abstraites peuvent avoir des méthodes statiques, de classe et d'instance. Mais en cas d'interface, il n'aura que des méthodes abstraites pas d'autres. Par conséquent, il n'est pas obligatoire d'hériter d'une classe abstraite, mais il est obligatoire d'hériter d'une interface.