Dieser Artikel ist der Artikel zum 8. Tag von Python Advent Calendar 2015.
Normalerweise schreibe ich Go und ehrlich gesagt schreibe ich selten Python. Ich denke darüber nach, es in der Mathematik zu verwenden, also bin ich dieses Mal in den Adventskalender von Python gesprungen.
In Go ist es jetzt wichtig, eine Schnittstelle zu definieren und in einem abstrahierten Muster für eine groß angelegte Entwicklung zu implementieren. Hier geht es nicht nur um Go, die Objekte werden abstrahiert, und es wird ein großartiger Code, der gut lesbar ist und bei bescheidener Verwendung geringe Abhängigkeiten aufweist.
In der Zwischenzeit habe ich untersucht, welche Methode für die Abstraktion in Python verfügbar ist. Verwenden Sie das Modul, das in der Sprachspezifikation nicht vorhanden ist und als Modul mit dem Namen ABC (Abstract Base Class) bereitgestellt wird.
In Python können abstrakte Klassen mithilfe des ABC-Moduls (Abstract Base Class) (https://docs.python.org/3.5/library/abc.html) implementiert werden. Die abstrakte Basisklasse kann durch eine Metaklasse namens ABCMeta definiert werden, und die definierte abstrakte Basisklasse kann als Oberklasse zum Definieren von Unterklassen verwendet werden.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
#Abstrakte Klasse
class Animal(metaclass=ABCMeta):
@abstractmethod
def sound(self):
pass
#Abstrakte Klasse erben
class Cat(Animal):
def sound(self):
print("Meow")
if __name__ == "__main__":
assert issubclass(Cat().__class__, Animal)
assert isinstance(Cat(), Animal)
Wir haben eine abstrakte Klasse namens "Animal" definiert und die "Cat" -Klasse implementiert, die sie geerbt hat. Da es vererbt wird, scheint es natürlich, dass "issubclass" und "isinstance" durchlaufen werden.
Wenn die geerbte "Cat" -Klasse den "Sound" der abstrakten Methode nicht implementiert (@abstractmethod wird später beschrieben), tritt ein Laufzeitfehler auf, wie unten gezeigt. (* Beim Erstellen einer Instanz)
class Cat(Animal):
pass
# TypeError: Can't instantiate abstract class Cat with abstract methods sound
Anstatt Unterklassen zu definieren, ist es andererseits möglich, nicht verwandte Klassen so zu registrieren, dass sie sich wie abstrakte Klassen verhalten. Dies wird als ** virtuelle Unterklasse ** bezeichnet.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta):
@abstractmethod
def sound(self):
pass
#Erbt die abstrakte Klasse nicht,`sound`Methode implementieren
class Dog():
def sound(self):
print("Bow")
#Registrieren Sie Hund zu Tier der abstrakten Klasse
Animal.register(Dog)
if __name__ == "__main__":
assert issubclass(Dog().__class__, Animal)
assert isinstance(Dog(), Animal)
Wenn Sie sich bei einer virtuellen Unterklasse registrieren, ist diese Klasse die einer abstrakten Klasse. Wenn die abstrakte Methode jedoch nicht implementiert ist, tritt ein Laufzeitfehler auf, wie unten gezeigt. (* Beim Aufrufen einer Methode)
class Dog():
pass
# AttributeError: 'Dog' object has no attribute 'sound'
@abstractmethod
Ein Dekorateur, der eine abstrakte Methode zeigt. Obwohl es sich um eine abstrakte Methode handelt, ist es auch möglich, den Prozess in einer Methode zu beschreiben, die einen Dekorateur angibt und aus einer Unterklasse aufruft.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta):
@abstractmethod
def sound(self):
print("Hello")
#Abstrakte Klasse erben
class Cat(Animal):
def sound(self):
#Rufen Sie den Sound der Vererbungsquelle auf
super(Cat, self).sound()
print("Meow")
if __name__ == "__main__":
print(Cat().sound())
Sie können die geerbte abstrakte Methode mit "super (Cat, self) .sound ()" aufrufen. Es ist ein bisschen anders als Java.
@abstractclassmethod
(version 3.2)
Es ist ein Dekorator der abstrakten Klassenmethode, wird jedoch ab Version 3.3 von @ classmethod
wie folgt beschrieben.
class Animal(metaclass=ABCMeta):
@classmethod
@abstractmethod
def sound_classmethod(self):
pass
@abstractstaticmethod
(version 3.2)
Es ist ein Dekorateur einer abstrakten statischen Methode, aber ab Version 3.3 wird es durch "@ staticmethod" wie folgt beschrieben.
class Animal(metaclass=ABCMeta):
@staticmethod
@abstractmethod
def sound_staticmethod(self):
pass
Das Obige reicht für abstrakte Klassen aus, aber ich wollte danach [Duck Typing](https://ja.wikipedia.org/wiki/Duck Typing) überprüfen, damit ich es implementieren kann. ..
„Wenn es wie eine Ente läuft und wie eine Ente quakt, muss es eine Ente sein." - „Wenn Sie wie eine Ente gehen und weinen, ist es eine Ente."
Es ist wie ein Name.
Vereinfachen wir dies und sagen: "Wenn Sie weinen, ist es ein Tier." Und wenn Sie es zwangsweise in die Programmierung einfügen: "Wenn Sie eine Methode namens" Weinen "für ein Objekt implementieren, ist die konkrete Klasse" Tier "." Es ist zum ersten Mal schwer zu verstehen.
Es ist schneller zu sehen als in deinem Kopf zu denken.
#!/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)
Wenn Sie like implementieren und ausführen, erhalten Sie das folgende Ergebnis und den folgenden Laufzeitfehler.
Cat: Meow
Dog: Bow
AttributeError: 'Book' object has no attribute 'sound'
"Buch" ohne "Ton" beim Entenschreiben ist in Ordnung, da es nicht "kein Ton = Tier" ist. Ich möchte den Fehler jedoch nach Möglichkeit erkennen. Ich kann das Gefühl nicht leugnen, dass dies dynamisches Tippen ist, aber ich möchte es nach Möglichkeit vermeiden, also werde ich Folgendes tun.
def output(animal):
print(animal.__class__.__name__, end=": ")
try:
animal.sound()
except AttributeError:
print('No sound')
Es ist eine Methode zum Abfangen, wenn eine Ausnahme mit "try" ausgespuckt wird. Da es sich jedoch um eine Ausführungsbasis handelt, kann sie erst behandelt werden, nachdem sie tatsächlich zu einer Ausnahme geworden ist. Ich kann es nicht sehr empfehlen.
def output(animal):
if not hasattr(animal, 'sound'):
return
print(animal.__class__.__name__, end=": ")
animal.sound()
Überprüft, ob das Attribut vorhanden ist. Nun, es ist vernünftig.
def output(animal):
if not isinstance(animal, Animal):
return
print(animal.__class__.__name__, end=": ")
animal.sound()
Bestimmt, ob die Klasse durch "isinstance" angegeben wird. Auf diese Weise können Sie die beabsichtigte abstrakte Klasse verarbeiten.
Es gab auch eine statische Tippprüfung mypy. Sie können sicher sein, wenn Sie an statisches Tippen gewöhnt sind.
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
Aber dynamisch typisierte Sprachen haben sich damit etabliert, so dass es sich subtil anfühlt, es noch statischer zu machen.
Es ist schön, abstrakte Klassen in Python implementieren zu können, aber ich kann nicht sagen, wann ein Fehler auftreten wird. Die Abstraktion ist interessant, da die Spezifikationen in jeder Sprache festgelegt sind, die Konzepte jedoch geringfügig voneinander abweichen. Ich fühle, dass ich die Eigenschaften der Sprache fühle.
Recommended Posts