Maison >développement back-end >Tutoriel Python >Définir et utiliser des classes abstraites en Python

Définir et utiliser des classes abstraites en Python

高洛峰
高洛峰original
2017-03-01 13:49:161469parcourir

Tout le monde connaît les classes abstraites en Java. En Python, nous pouvons utiliser le module abc pour créer des classes abstraites. Nous expliquerons ici comment définir et utiliser des classes abstraites en Python

Python est comme Java. peut également définir une classe abstraite.

Avant de parler de classes abstraites, parlons de la mise en œuvre de méthodes abstraites.

Les méthodes abstraites sont des méthodes définies dans la classe de base mais sans aucune implémentation. En Java, vous pouvez déclarer une méthode comme interface. Le moyen simple d'implémenter une méthode abstraite en python est :

class Sheep(object):
  def get_size(self):
    raise NotImplementedError

Toute sous-classe héritée de Sheep doit implémenter la méthode get_size. Sinon, une erreur sera générée. Mais cette méthode de mise en œuvre présente un inconvénient. La sous-classe définie ne générera une erreur que lorsque cette méthode sera appelée. Voici un moyen simple de le déclencher une fois la classe instanciée. Utilisez le module abc fourni par python.

import abc
class Sheep(object):
  __metaclass__ = abc.ABCMeta
  
  @abc.absractmethod
  def get_size(self):
    return


Une exception sera levée lors de l'instanciation de la classe Sheep ou de toute sous-classe héritée de celle-ci (get_size n'est pas implémenté).

Ainsi, en définissant une classe abstraite, vous pouvez définir des méthodes communes aux sous-classes (forçant leur implémentation).

Comment utiliser les classes abstraites

import abc 

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def load(self, input):
    return 

  @abc.abstractmethod
  def save(self, output, data):
    return

Créez une classe abstraite via la métaclasse ABCMeta et décorez-la avec abstractmethod Conteneur pour indiquer une méthode abstraite

Enregistrer une classe concrète

class B(object):
  
  def load(self, input):
    return input.read()

  def save(self, output, data):
    return output.write(data)

A.register(B)

if __name__ == '__main__':
  print issubclass(B, A)   # print True
  print isinstance(B(), A)  # print True

Enregistrer une classe concrète à partir d'un classe abstraite

Implémentation de sous-classe

class C(A):

  def load(self, input):
    return input.read()

  def save(self, output, data):
    return output.write(data)
    
if __name__ == '__main__':
  print issubclass(C, A)   # print True
  print isinstance(C(), A)  # print True

Vous pouvez utiliser la méthode d'héritage de la classe abstraite pour implémenter la classe concrète. Cela peut éviter d'utiliser le registre. Mais l'effet secondaire est que vous pouvez trouver toutes les classes concrètes via la classe de base

for sc in A.__subclasses__():
  print sc.__name__

# print C

Si vous utilisez l'héritage. , vous trouverez toutes les classes concrètes. Si vous utilisez register, elle ne sera pas trouvée

Utilisez __subclasshook__

Après avoir utilisé __subclasshook__, tant que la classe concrète définit le même méthode que la classe abstraite, elle sera considérée comme sa sous-classe

import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def say(self):
    return 'say yeah'

  @classmethod
  def __subclasshook__(cls, C):
    if cls is A:
      if any("say" in B.__dict__ for B in C.__mro__):
        return True
    return NotTmplementd

class B(object):
  def say(self):
    return 'hello'

print issubclass(B, A)   # True
print isinstance(B(), A)  # True
print B.__dict__      # {&#39;say&#39;: <function say at 0x7f...>, ...}
print A.__subclasshook__(B) # True

Implémentation incomplète

class D(A):
  def save(self, output, data):
    return output.write(data)

if __name__ == &#39;__main__&#39;:
  print issubclass(D, A)   # print True
  print isinstance(D(), A)  # raise TypeError

Si vous construisez une classe concrète incomplète, elle lancera D. Impossible d'instancier des classes abstraites et des méthodes abstraites

Utiliser des classes de base abstraites dans des classes concrètes

import abc 
from cStringIO import StringIO

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def retrieve_values(self, input):
    pirnt &#39;base class reading data&#39;
    return input.read()


class B(A):

  def retrieve_values(self, input):
    base_data = super(B, self).retrieve_values(input)
    print &#39;subclass sorting data&#39;
    response = sorted(base_data.splitlines())
    return response

input = StringIO("""line one
line two
line three
""")

reader = B()
print reader.retrieve_values(input)

Imprimer les résultats

base class reading data
subclass sorting data
[&#39;line one&#39;, &#39;line two&#39;, &#39;line three&#39;]

Vous pouvez utiliser super pour réutiliser la logique dans la classe de base abstraite, mais cela forcera l'enfant. La classe fournit des méthodes de substitution

Attribut abstrait

import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractproperty
  def value(self):
    return &#39;should never get here.&#39;

class B(A):
  
  @property
  def value(self):
    return &#39;concrete property.&#39;

try:
  a = A()
  print &#39;A.value&#39;, a.value
except Exception, err:
  print &#39;Error: &#39;, str(err)

b = B()
print &#39;B.value&#39;, b.value

.

Imprimez le résultat, A ne peut pas être instancié car il n'y a qu'une seule méthode d'obtention de propriété abstraite.

Error: ...
print concrete property

Définir la lecture et l'écriture abstraites propriétés

import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  def value_getter(self):
    return &#39;Should never see this.&#39;

  def value_setter(self, value):
    return 

  value = abc.abstractproperty(value_getter, value_setter)

class B(A):
  
  @abc.abstractproperty
  def value(self):
    return &#39;read-only&#39;

class C(A):
  _value = &#39;default value&#39;

  def value_getter(self):
    return self._value

  def value_setter(self, value):
    self._value = value

  value = property(value_getter, value_setter)

try:
  a = A()
  print a.value
except Exception, err:
  print str(err)

try:
  b = B()
  print b.value
except Exception, err:
  print str(err)

c = C()
print c.value

c.value = &#39;hello&#39;
print c.value

Imprimer le résultat Lors de la définition de la propriété de la classe concrète, elle doit être la même que la propriété abstraite. Cela ne fonctionnera pas si vous n'en remplacez qu'un seul

error: ...
error: ...
print &#39;default value&#39;
print &#39;hello&#39;

Utilisez la syntaxe du décorateur pour implémenter les propriétés abstraites de lecture et d'écriture. l'écriture devrait être la même .

import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractproperty
  def value(self):
    return &#39;should never see this.&#39;

  @value.setter
  def value(self, _value):
    return 

class B(A):
  _value = &#39;default&#39;

  @property
  def value(self):
    return self._value

  @value.setter
  def value(self, _value):
    self._value = _value

b = B()
print b.value    # print &#39;default&#39;

b.value = &#39;hello&#39;
print b.value    # print &#39;hello&#39;


Pour plus d'articles liés à la définition et à l'utilisation de classes abstraites en Python, veuillez faites attention au site Web PHP chinois !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn