Dans le code suivant, je crée une classe abstraite de base Base
. Je veux que toutes les classes qui héritent de Base
fournissent la propriété name
, j'ai donc fait de cette propriété un @abstractmethod
.
J'ai ensuite créé une sous-classe de Base
, appelée Base_1
, qui est censé fournir certaines fonctionnalités, mais reste abstrait. Il n'y a pas de propriété name
dans Base_1
, mais néanmoins python installe un objet de cette classe sans erreur. Comment créer des propriétés abstraites?
from abc import ABCMeta, abstractmethod
class Base(object):
__metaclass__ = ABCMeta
def __init__(self, strDirConfig):
self.strDirConfig = strDirConfig
@abstractmethod
def _doStuff(self, signals):
pass
@property
@abstractmethod
def name(self):
#this property will be supplied by the inheriting classes
#individually
pass
class Base_1(Base):
__metaclass__ = ABCMeta
# this class does not provide the name property, should raise an error
def __init__(self, strDirConfig):
super(Base_1, self).__init__(strDirConfig)
def _doStuff(self, signals):
print 'Base_1 does stuff'
class C(Base_1):
@property
def name(self):
return 'class C'
if __== '__main__':
b1 = Base_1('abc')
Depuis Python 3. , un bug a été corrigé, ce qui signifie que le décorateur property()
est désormais correctement identifié comme abstrait lorsqu'il est appliqué à une méthode abstraite.
Remarque: les commandes sont importantes, vous devez utiliser @property
avant @abstractmethod
Python 3.3 +: ( documents python ):
class C(ABC):
@property
@abstractmethod
def my_abstract_property(self):
...
Python 2: ( documents python )
class C(ABC):
@abstractproperty
def my_abstract_property(self):
...
Jusqu'à Python 3. , vous ne pouvez pas imbriquer @abstractmethod
et @property
.
Utilisation @abstractproperty
pour créer des propriétés abstraites ( docs ).
from abc import ABCMeta, abstractmethod, abstractproperty
class Base(object):
# ...
@abstractproperty
def name(self):
pass
Le code lève maintenant l'exception correcte:
Traceback (dernier appel le plus récent): Fichier "foo.py", ligne 36, dans B1 = Base_1 ('abc') TypeError: Can 'instanciez pas la classe abstraite Base_1 avec le nom des méthodes abstraites
Basé sur la réponse de James ci-dessus
def compatibleabstractproperty(func):
if sys.version_info > (3, 3):
return property(abstractmethod(func))
else:
return abstractproperty(func)
et l'utiliser comme décorateur
@compatibleabstractproperty
def env(self):
raise NotImplementedError()