Man könnte auch einen tun raise NotImplementedError()
innerhalb des Kindes Methode einer @abstractmethod
-Dekoriert Basisklassenmethode.
Stellen Sie sich vor, Sie schreiben ein Steuerungsskript für eine Familie von Messmodulen (physische Geräte). Die Funktionalität jedes Moduls ist eng definiert und implementiert nur eine spezielle Funktion: Eine kann ein Array von Relais sein, eine andere ein Mehrkanal-DAC oder ADC, eine andere ein Amperemeter usw.
Ein Großteil der verwendeten Befehle auf niedriger Ebene würde von den Modulen gemeinsam genutzt, um beispielsweise ihre ID-Nummern zu lesen oder einen Befehl an sie zu senden. Mal sehen, was wir an dieser Stelle haben:
Basisklasse
from abc import ABC, abstractmethod
class Generic(ABC):
''' Base class for all measurement modules. '''
def __init__(self):
def _read_ID(self):
def _send_command(self, value):
Geteilte Verben
Wir erkennen dann, dass ein Großteil der modulspezifischen Befehlsverben und damit auch die Logik ihrer Schnittstellen geteilt wird. Hier sind 3 verschiedene Verben, deren Bedeutung unter Berücksichtigung einer Reihe von Zielmodulen selbsterklärend wäre.
get(channel)
Relais: Schaltet den Ein / Aus-Status des Relais einchannel
DAC: Schalten Sie die Ausgangsspannung einchannel
ADC: Schalten Sie die Eingangsspannung einchannel
enable(channel)
Relais: Aktivieren Sie die Verwendung des Relais anchannel
DAC: Aktivieren Sie die Verwendung des Ausgangskanals einchannel
ADC: Aktivieren Sie die Verwendung des Eingangskanals einchannel
set(channel)
Relais: Relais channel
ein- / ausschalten
DAC: Schalten Sie die Ausgangsspannung einchannel
ADC: hmm ... mir fällt nichts Logisches ein .
Geteilte Verben werden zu erzwungenen Verben
Ich würde argumentieren, dass es ein starkes Argument dafür gibt, dass die oben genannten Verben über die Module hinweg geteilt werden, da wir gesehen haben, dass ihre Bedeutung für jedes einzelne von ihnen offensichtlich ist. Ich würde meine Basisklasse Generic
so weiter schreiben :
class Generic(ABC):
@abstractmethod
def get(self, channel):
pass
@abstractmethod
def enable(self, channel):
pass
@abstractmethod
def set(self, channel):
pass
Unterklassen
Wir wissen jetzt, dass unsere Unterklassen alle diese Methoden definieren müssen. Mal sehen, wie es für das ADC-Modul aussehen könnte:
class ADC(Generic):
def __init__(self):
super().__init__()
def get(self, channel):
def enable(self, channel):
Sie fragen sich jetzt vielleicht:
Dies funktioniert jedoch nicht für das ADC- Modul, da set
es dort keinen Sinn ergibt, wie wir dies oben gesehen haben!
Sie haben Recht: Nicht zu implementieren set
ist keine Option, da Python dann den folgenden Fehler auslösen würde, wenn Sie versuchen, Ihr ADC-Objekt zu instanziieren.
TypeError: Can't instantiate abstract class 'ADC' with abstract methods 'set'
Sie müssen also etwas implementieren, da wir set
ein erzwungenes Verb (auch bekannt als '@abstractmethod') erstellt haben, das von zwei anderen Modulen gemeinsam genutzt wird. Gleichzeitig dürfen Sie jedoch auch nichts implementieren, was
set
für dieses bestimmte Modul keinen Sinn ergibt.
NotImplementedError zur Rettung
Wenn Sie die ADC-Klasse wie folgt abschließen:
class ADC(Generic):
def set(self, channel):
raise NotImplementedError("Can't use 'set' on an ADC!")
Sie machen drei sehr gute Dinge gleichzeitig:
- Sie schützen einen Benutzer davor, fälschlicherweise einen Befehl ('set') auszugeben, der für dieses Modul nicht implementiert ist (und nicht implementiert werden sollte!).
- Sie sagen ihnen explizit, wo das Problem liegt (siehe TemporalWolfs Link zu 'Nackte Ausnahmen', warum dies wichtig ist)
- Sie schützen die Implementierung aller anderen Module, für die die erzwungenen Verben
sinnvoll sind. Dh Sie sicher , dass diese Module , für die diese Verben tun sinnvoll , diese Methoden implementieren und dass sie tun werden , so mit genau diese Verben und nicht einige andere Ad-hoc - Namen.