web-dev-qa-db-fra.com

Comment créer des propriétés abstraites dans python classes abstraites

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')  
71
Boris Gorelik

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):
        ...
52
James

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 
41
codeape

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()
0
himanshu219