Comment puis-je créer une classe ou une méthode abstraite en Python?
J'ai essayé de redéfinir __new__()
comme ça:
class F:
def __new__(cls):
raise Exception("Unable to create an instance of abstract class %s" %cls)
mais maintenant si je crée une classe G
qui hérite de F
comme ça:
class G(F):
pass
alors je ne peux pas non plus instancier G
, car il appelle la __new__
méthode de sa super classe .
Existe-t-il une meilleure façon de définir une classe abstraite?
python
class
inheritance
abstract-class
abstract
Martin Thoma
la source
la source
Réponses:
Utilisez le
abc
module pour créer des classes abstraites. Utilisez leabstractmethod
décorateur pour déclarer un résumé de méthode, et déclarez un résumé de classe en utilisant l'une des trois façons, selon votre version Python.Dans Python 3.4 et supérieur, vous pouvez hériter de
ABC
. Dans les versions antérieures de Python, vous devez spécifier la métaclasse de votre classe en tant queABCMeta
. La spécification de la métaclasse a une syntaxe différente dans Python 3 et Python 2. Les trois possibilités sont présentées ci-dessous:Quelle que soit la façon dont vous utilisez, vous ne pourrez pas instancier une classe abstraite qui a des méthodes abstraites, mais pourrez instancier une sous-classe qui fournit des définitions concrètes de ces méthodes:
la source
@abstractmethod
fait en sorte que la fonction décorée doit être remplacée avant que la classe puisse être instanciée. De la documentation:A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden.
@abstractmethod
pour la__init__
méthode aussi bien, voir stackoverflow.com/q/44800659/547270La méthode old-school (pré- PEP 3119 ) consiste à utiliser
raise NotImplementedError
la classe abstraite lorsqu'une méthode abstraite est appelée.Cela n'a pas les mêmes propriétés intéressantes que l'utilisation du
abc
module. Vous pouvez toujours instancier la classe de base abstraite elle-même, et vous ne trouverez votre erreur que lorsque vous appellerez la méthode abstraite au moment de l'exécution.Mais si vous traitez avec un petit ensemble de classes simples, peut-être avec seulement quelques méthodes abstraites, cette approche est un peu plus facile que d'essayer de parcourir la
abc
documentation.la source
Voici un moyen très simple sans avoir à gérer le module ABC.
Dans la
__init__
méthode de la classe que vous voulez être une classe abstraite, vous pouvez vérifier le "type" de soi. Si le type de self est la classe de base, alors l'appelant essaie d'instancier la classe de base, alors lève une exception. Voici un exemple simple:Lorsqu'il est exécuté, il produit:
Cela montre que vous pouvez instancier une sous-classe qui hérite d'une classe de base, mais vous ne pouvez pas instancier directement la classe de base.
la source
La plupart des réponses précédentes étaient correctes mais voici la réponse et l'exemple pour Python 3.7. Oui, vous pouvez créer une classe et une méthode abstraites. À titre de rappel, une classe doit parfois définir une méthode qui appartient logiquement à une classe, mais cette classe ne peut pas spécifier comment implémenter la méthode. Par exemple, dans les classes Parents et Bébés ci-dessous, ils mangent tous les deux, mais la mise en œuvre sera différente pour chacun, car les bébés et les parents mangent un type de nourriture différent et le nombre de fois qu'ils mangent est différent. Ainsi, les sous-classes de méthode eat remplacent AbstractClass.eat.
PRODUCTION:
la source
import abc
- être est inutile.Celui-ci fonctionnera en python 3
la source
Comme expliqué dans les autres réponses, oui, vous pouvez utiliser des classes abstraites en Python en utilisant le
abc
module . Ci - dessous je donne un exemple réel à l' aide abstraite@classmethod
,@property
et@abstractmethod
( en utilisant Python 3.6+). Pour moi, il est généralement plus facile de commencer avec des exemples que je peux facilement copier et coller; J'espère que cette réponse est également utile pour d'autres.Créons d'abord une classe de base appelée
Base
:Notre
Base
classe aura toujours unfrom_dict
classmethod
, unproperty
prop1
(qui est en lecture seule) et unproperty
prop2
(qui peut également être défini) ainsi qu'une fonction appeléedo_stuff
. Quelle que soit la classe qui est maintenant construite, elleBase
devra implémenter tout cela pour les méthodes / propriétés. Veuillez noter que pour qu'une méthode soit abstraite, deux décorateurs sont requis -classmethod
et abstraitsproperty
.Maintenant, nous pourrions créer une classe
A
comme celle-ci:Toutes les méthodes / propriétés requises sont implémentées et nous pouvons - bien sûr - également ajouter des fonctions supplémentaires qui ne font pas partie
Base
(ici:)i_am_not_abstract
.Maintenant, nous pouvons faire:
Comme souhaité, nous ne pouvons pas définir
prop1
:reviendra
Notre
from_dict
méthode fonctionne également très bien:Si nous définissons maintenant une deuxième classe
B
comme celle-ci:et a essayé d'instancier un objet comme celui-ci:
nous obtiendrons une erreur
répertoriant toutes les choses définies dans
Base
lesquelles nous n'avons pas implémentéB
.la source
cela fonctionne aussi et est simple:
la source
Vous pouvez également exploiter la méthode __new__ à votre avantage. Tu as juste oublié quelque chose. La méthode __new__ renvoie toujours le nouvel objet, vous devez donc renvoyer la nouvelle méthode de sa superclasse. Procédez comme suit.
Lorsque vous utilisez la nouvelle méthode, vous devez renvoyer l'objet, pas le mot clé None. C'est tout ce que tu as manqué.
la source
Je trouve la réponse acceptée, et toutes les autres étranges, puisqu'elles passent
self
en classe abstraite. Une classe abstraite n'est pas instanciée et ne peut donc pas avoir deself
.Alors essayez ça, ça marche.
la source
la source
Dans votre extrait de code, vous pouvez également résoudre ce problème en fournissant une implémentation de la
__new__
méthode dans la sous-classe, de la même manière:Mais c'est un hack et je vous déconseille, à moins que vous sachiez ce que vous faites. Pour presque tous les cas, je vous conseille d'utiliser le
abc
module, que d'autres avant moi ont suggéré.De même , lorsque vous créez une nouvelle classe, faire la sous - classe (base)
object
, comme ceci:class MyBaseClass(object):
. Je ne sais plus si c'est beaucoup plus important, mais cela aide à conserver la cohérence du style sur votre codela source
Juste un ajout rapide à la réponse old-school de @ TimGilbert ... vous pouvez faire en sorte que la méthode init () de votre classe de base abstraite lève une exception et cela l'empêcherait d'être instanciée, non?
la source