Réponses:
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" )
Parce que 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 fait l'effort de définir une interface formelle, ce sera aussi une classe abstraite. Les seules différences seraient dans l'intention déclarée dans la docstring.
Et la différence entre l'abstrait et l'interface est une chose à couper les cheveux lorsque vous avez tapé du canard.
Java utilise des interfaces car il n'a pas d'héritage multiple.
Parce que Python a un héritage multiple, vous pouvez également voir quelque chose comme ça
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 superclasse abstraite avec des mixins pour créer des sous-classes concrètes disjointes.
NotImplementedError("Class %s doesn't implement aMethod()" % (self.__class__.__name__))
est un message d'erreur plus informatif :)
Quelle est la différence entre la classe abstraite et l'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, disons que nous voulons utiliser l'une des classes de base abstraites du collections
module:
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 sommes donc tenus de mettre en œuvre au moins __contains__
, __iter__
et __len__
. Utilisons cet exemple d'implémentation de la 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 abc.abstractmethod
décorateur sur les méthodes pertinentes. La métaclasse ajoutera les fonctions décorées à l' __abstractmethods__
attribut, empêchant l'instanciation jusqu'à ce qu'elles soient définies.
import abc
Par exemple, "effable" est défini comme quelque chose qui peut être exprimé en 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 en Python 3, avec le léger changement de 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 terminé le travail.
Maintenant, si nous nous conformons en fournissant l'interface attendue:
class MyEffable(Effable):
def __str__(self):
return 'expressable!'
on peut alors utiliser la version concrète de la classe dérivée de la classe abstraite:
>>> me = MyEffable()
>>> print(me)
expressable!
Il y a d'autres choses que nous pourrions faire 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 devraient adapter cette méthode en utilisant leabc
module.
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 des classes de base abstraites .
Les classes de base abstraites (ABC abrégés) complètent le typage canard en fournissant un moyen de définir des interfaces lorsque d'autres techniques comme 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 nombres) 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 des 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 ou d'interfaces en python (édité - voir la réponse de S.Lott pour plus de détails).
Python n'a pas vraiment de concept.
Il utilise le typage canard, ce qui a supprimé le besoin d'interfaces (au moins pour l'ordinateur :-))
Python <= 2.5: Les classes de base existent évidemment, mais il n'y a aucun moyen explicite de marquer une méthode comme 'virtuelle pure', donc la classe n'est pas vraiment abstraite.
Python> = 2.6: des classes de base abstraites existent ( http://docs.python.org/library/abc.html ). Et vous permettent de spécifier des 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 frappe de canard du côté client «utilisant».
D'une manière plus simple à expliquer: Une interface est un peu comme un moule à muffins vide. Il s'agit d'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 n'ont pas besoin d'être vides. Certains peuvent avoir du code. Ce n'est pas strictement vide.
Pourquoi différencier: Il n'y a 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'y a pas de code. Surtout si vous travaillez avec des programmeurs Java habitués au terme.
En général, les interfaces sont utilisées uniquement dans les langages qui utilisent 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. Toujours dans ces langages à héritage unique, les classes abstraites sont utilisées pour avoir des variables de classe définies en plus d’aucune ou plusieurs méthodes, ou pour exploiter le modèle d’héritage unique pour limiter la gamme de classes qui pourraient utiliser un ensemble de méthodes.
Les langages qui prennent en charge le modèle à héritage multiple 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'interfaces 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. En plus des 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 les autres. Par conséquent, il n'est pas obligatoire d'hériter de la classe abstraite mais il est obligatoire d'hériter de l'interface.
Pour être complet, nous devons mentionner PEP3119 où ABC a été introduit et comparé aux interfaces, et le commentaire original de Talin .
La classe abstraite n'est pas une interface parfaite:
Mais si vous envisagez de l'écrire à votre façon:
def some_function(self):
raise NotImplementedError()
interface = type(
'your_interface', (object,),
{'extra_func': some_function,
'__slots__': ['extra_func', ...]
...
'__instancecheck__': your_instance_checker,
'__subclasscheck__': your_subclass_checker
...
}
)
ok, rather as a class
or as a metaclass
and fighting with python to achieve the immutable object
and doing refactoring
...
vous réaliserez assez rapidement que vous inventez la roue pour finalement atteindre
abc.ABCMeta
abc.ABCMeta
a été proposé comme un ajout utile de la fonctionnalité d'interface manquante, et c'est assez juste dans un langage comme python.
Certes, il a pu être amélioré davantage lors de l'écriture de la version 3, et en ajoutant une nouvelle syntaxe et un concept d'interface immuable ...
Conclusion:
The abc.ABCMeta IS "pythonic" interface in python