Soll es Sie und Ihr Team daran erinnern, die Klasse korrekt zu implementieren? Ich kann eine abstrakte Klasse wie diese nicht vollständig verwenden:
class RectangularRoom(object):
def __init__(self, width, height):
raise NotImplementedError
def cleanTileAtPosition(self, pos):
raise NotImplementedError
def isTileCleaned(self, m, n):
raise NotImplementedError
Antworten:
Wie in der Dokumentation [docs] angegeben ,
Beachten Sie, dass der Hauptanwendungsfall dieser Fehler zwar die Angabe abstrakter Methoden ist, die für geerbte Klassen implementiert werden sollen, Sie ihn jedoch beliebig verwenden können, beispielsweise zur Angabe eines
TODO
Markers.quelle
abc
(siehe meine Antwort ).abstractmethod
und anheben lassenNotImplementedError
. Dies verbietetsuper().method()
bei Implementierungenmethod
in abgeleiteten Klassen.Wie Uriel sagt , ist es für eine Methode in einer abstrakten Klasse gedacht, die in einer untergeordneten Klasse implementiert werden sollte, aber auch zur Angabe eines TODO verwendet werden kann.
Für den ersten Anwendungsfall gibt es eine Alternative: Abstrakte Basisklassen . Diese helfen beim Erstellen abstrakter Klassen.
Hier ist ein Python 3-Beispiel:
class C(abc.ABC): @abstractmethod def my_abstract_method(self, ...): ...
Beim Instanziieren
C
wird eine Fehlermeldung angezeigt , da diesemy_abstract_method
abstrakt ist. Sie müssen es in einer untergeordneten Klasse implementieren.TypeError: Can't instantiate abstract class C with abstract methods my_abstract_method
Unterklasse
C
und implementierenmy_abstract_method
.class D(C): def my_abstract_method(self, ...): ...
Jetzt können Sie instanziieren
D
.C.my_abstract_method
muss nicht leer sein. Es kann vonD
using aufgerufen werdensuper()
.Dies hat den Vorteil,
NotImplementedError
dass SieException
zur Instanziierungszeit eine explizite und nicht zur Methodenaufrufzeit erhalten.quelle
from abc import ABCMeta, abstractmethod
und definieren Sie Ihr ABC mit__metaclass__ = ABCMeta
. Docs: docs.python.org/2/library/abc.htmlÜberlegen Sie, ob es stattdessen war:
class RectangularRoom(object): def __init__(self, width, height): pass def cleanTileAtPosition(self, pos): pass def isTileCleaned(self, m, n): pass
und Sie unterordnen und vergessen, es zu sagen, wie
isTileCleaned()
oder, vielleicht wahrscheinlicher, alsisTileCLeaned()
. Dann erhalten Sie in Ihrem Code eine,None
wenn Sie ihn aufrufen.None
gültige Ausgabe? Wer weiß.raise NotImplmentedError
Kräfte Sie es implementieren, da es wird eine Ausnahme ausgelöst , wenn Sie versuchen , es zu laufen , bis Sie das tun. Dies beseitigt viele stille Fehler. Es ist ähnlich, warum eine nackte Ausnahme fast nie eine gute Idee ist : weil Menschen Fehler machen und dies sicherstellt, dass sie nicht unter den Teppich gekehrt werden.Hinweis: Die Verwendung einer abstrakten Basisklasse ist, wie bereits in anderen Antworten erwähnt, noch besser, da die Fehler vorab geladen werden und das Programm erst ausgeführt wird, wenn Sie sie implementieren (mit NotImplementedError wird nur dann eine Ausnahme ausgelöst, wenn sie tatsächlich aufgerufen wird).
quelle
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 #< we'll make use of these later class Generic(ABC): ''' Base class for all measurement modules. ''' # Shared functions def __init__(self): # do what you must... def _read_ID(self): # same for all the modules def _send_command(self, value): # same for all the modules
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 ein
channel
DAC: Schalten Sie die Ausgangsspannung ein
channel
ADC: Schalten Sie die Eingangsspannung ein
channel
enable(channel)
Relais: Aktivieren Sie die Verwendung des Relais an
channel
DAC: Aktivieren Sie die Verwendung des Ausgangskanals ein
channel
ADC: Aktivieren Sie die Verwendung des Eingangskanals ein
channel
set(channel)
Relais: Relais
channel
ein- / ausschaltenDAC: Schalten Sie die Ausgangsspannung ein
channel
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): # ...continued @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__() #< applies to all modules # more init code specific to the ADC module def get(self, channel): # returns the input voltage measured on the given 'channel' def enable(self, channel): # enables accessing the given 'channel'
Sie fragen sich jetzt vielleicht:
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, wasset
für dieses bestimmte Modul keinen Sinn ergibt.NotImplementedError zur Rettung
Wenn Sie die ADC-Klasse wie folgt abschließen:
class ADC(Generic): # ...continued def set(self, channel): raise NotImplementedError("Can't use 'set' on an ADC!")
Sie machen drei sehr gute Dinge gleichzeitig:
quelle
Vielleicht möchten Sie den
@property
Dekorateur verwenden,>>> class Foo(): ... @property ... def todo(self): ... raise NotImplementedError("To be implemented") ... >>> f = Foo() >>> f.todo Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in todo NotImplementedError: To be implemented
quelle