Cet article est l'article du 8ème jour du Calendrier de l'Avent Python 2015.
J'écris habituellement Go, et honnêtement, j'écris rarement Python. Je pense l'utiliser en mathématiques, alors j'ai sauté dans le calendrier de l'Avent de Python cette fois.
Désormais, dans Go, il est important de définir une interface et de l'implémenter dans un modèle abstrait pour un développement à grande échelle. Il ne s'agit pas seulement de Go, les objets sont abstraits, et c'est un excellent code plus lisible et moins dépendant d'une utilisation modeste.
Pendant ce temps, j'ai étudié le type de méthode disponible pour l'abstraction en Python. Utilisez celui qui n'existe pas dans la spécification du langage et qui est fourni sous la forme d'un module nommé ABC (Abstract Base Class).
En Python, les classes abstraites peuvent être implémentées à l'aide du module ABC (Abstract Base Class) (https://docs.python.org/3.5/library/abc.html). La classe de base abstraite peut être définie par une métaclasse appelée ABCMeta, et la classe de base abstraite définie peut être utilisée comme une superclasse pour définir des sous-classes.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
#Classe abstraite
class Animal(metaclass=ABCMeta):
@abstractmethod
def sound(self):
pass
#Hériter de la classe abstraite
class Cat(Animal):
def sound(self):
print("Meow")
if __name__ == "__main__":
assert issubclass(Cat().__class__, Animal)
assert isinstance(Cat(), Animal)
Nous avons défini une classe abstraite appelée ʻAnimal et implémenté la classe
Cat qui en a hérité. Puisqu'il est hérité, il semble naturel que ʻis sous-classe
, ʻis instance` passe.
Si la classe héritée Cat
n'implémente pas le son
de la méthode abstraite (@abstractmethod sera décrite plus tard), une erreur d'exécution se produira comme indiqué ci-dessous. (* Lors de la création d'une instance)
class Cat(Animal):
pass
# TypeError: Can't instantiate abstract class Cat with abstract methods sound
register
D'un autre côté, au lieu de définir des sous-classes, il est possible d'enregistrer des classes non liées pour se comporter comme des classes abstraites. C'est ce qu'on appelle une ** sous-classe virtuelle **.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta):
@abstractmethod
def sound(self):
pass
#N'hérite pas de la classe abstraite,`sound`Mettre en œuvre la méthode
class Dog():
def sound(self):
print("Bow")
#Enregistrer un chien à un animal de classe abstraite
Animal.register(Dog)
if __name__ == "__main__":
assert issubclass(Dog().__class__, Animal)
assert isinstance(Dog(), Animal)
Si vous vous inscrivez dans une sous-classe virtuelle, cette classe sera celle d'une classe abstraite, mais si la méthode abstraite n'est pas implémentée, une erreur d'exécution se produira comme indiqué ci-dessous. (* Lors de l'appel d'une méthode)
class Dog():
pass
# AttributeError: 'Dog' object has no attribute 'sound'
@abstractmethod
Un décorateur qui montre une méthode abstraite. Bien qu'il s'agisse d'une méthode abstraite, il est également possible de décrire le processus dans une méthode qui spécifie un décorateur et de l'appeler à partir d'une sous-classe.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta):
@abstractmethod
def sound(self):
print("Hello")
#Hériter de la classe abstraite
class Cat(Animal):
def sound(self):
#Appelez le son de la source d'héritage
super(Cat, self).sound()
print("Meow")
if __name__ == "__main__":
print(Cat().sound())
Vous pouvez appeler la méthode abstraite héritée avec super (Cat, self) .sound ()
. C'est un peu différent de Java.
@abstractclassmethod
(version 3.2)
C'est un décorateur de la méthode de classe abstraite, mais à partir de la version 3.3, il est décrit par @ classmethod
comme suit.
class Animal(metaclass=ABCMeta):
@classmethod
@abstractmethod
def sound_classmethod(self):
pass
@abstractstaticmethod
(version 3.2)
C'est un décorateur d'une méthode statique abstraite, mais à partir de la version 3.3, il est décrit par @ staticmethod
comme suit.
class Animal(metaclass=ABCMeta):
@staticmethod
@abstractmethod
def sound_staticmethod(self):
pass
Ce qui précède est suffisant pour les classes abstraites, mais je voulais vérifier [Duck Typing](https://ja.wikipedia.org/wiki/Duck Typing) après cela, donc je vais l'implémenter. ..
"S'il marche comme un canard et charlatan comme un canard, ce doit être un canard." - "Si vous marchez comme un canard et pleurez, c'est un canard."
C'est un peu comme un nom.
Simplifions cela et disons: «Si vous pleurez, c'est un animal». Et si vous le mettez de force dans la programmation, "Si vous implémentez une méthode appelée" pleurer "sur un objet, la classe concrète sera" animal "." C'est difficile à comprendre pour la première fois.
C'est plus rapide de voir que de penser dans sa tête.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta):
@abstractmethod
def sound(self):
pass
class Cat(Animal):
def sound(self):
print("Meow")
class Dog():
def sound(self):
print("Bow")
class Book():
pass
Animal.register(Dog)
def output(animal):
print(animal.__class__.__name__, end=": ")
animal.sound()
if __name__ == "__main__":
c = Cat()
output(c)
d = Dog()
output(d)
b = Book()
output(b)
Si vous implémentez et exécutez comme, vous obtiendrez le résultat et l'erreur d'exécution suivants.
Cat: Meow
Dog: Bow
AttributeError: 'Book' object has no attribute 'sound'
La saisie de canard est correcte car «Livre» sans «son» n'est pas «pas de son = animal». Cependant, je voudrais détecter l'erreur si possible. Je ne peux pas nier le sentiment qu'il s'agit de frappe dynamique, mais j'aimerais éviter cela si possible, alors je vais faire ce qui suit.
try
~ ʻexcept`def output(animal):
print(animal.__class__.__name__, end=": ")
try:
animal.sound()
except AttributeError:
print('No sound')
C'est une méthode pour détecter si une exception est crachée avec try
, mais comme il s'agit d'une base d'exécution, elle ne peut être gérée qu'après qu'elle devienne réellement une exception. Je ne peux pas le recommander beaucoup.
hasattr
def output(animal):
if not hasattr(animal, 'sound'):
return
print(animal.__class__.__name__, end=": ")
animal.sound()
Vérifie si l'attribut existe. Eh bien, c'est raisonnable.
def output(animal):
if not isinstance(animal, Animal):
return
print(animal.__class__.__name__, end=": ")
animal.sound()
Détermine si la classe est spécifiée par ʻis instance`. Cela vous permettra de gérer la classe abstraite prévue.
Il y avait aussi une vérification de typage statique appelée mypy. Vous pouvez être assuré si vous êtes habitué à la saisie statique.
From Python...
def fib(n):
a, b = 0, 1
while a < n:
yield a
a, b = b, a+b
...to statically typed Python
def fib(n: int) -> Iterator[int]:
a, b = 0, 1
while a < n:
yield a
a, b = b, a+b
Mais les langages typés dynamiquement s'y sont établis, il est donc subtil de les rendre statiques.
C'est bien de pouvoir implémenter des classes abstraites en Python, mais je ne peux pas dire quand une erreur se produira. Quant à l'abstraction, elle est intéressante car les spécifications sont fixées dans chaque langue mais les concepts sont légèrement différents. Je sens que je ressens les caractéristiques de la langue.
Recommended Posts