warum leere Funktion benötigt werden

9

Ich habe angefangen, Python zu lernen und frage mich, warum in einer Programmiersprache leere Funktionen benötigt werden

zB in Python:

def empty_func():
    pass

Auch in Shell-Skripten stehen leere Funktionen zur Verfügung.

Mein Verständnis und meine Frage:

  1. Warum brauchte die Programmiersprache leere Funktionen? Ist es nur zum Herumspielen mit der Programmiersprache oder nichts anderes, was wirklich wichtig ist?

  2. Wenn dies einen Zweck hat, kann jemand den Anwendungsfall beschreiben oder ein reales Beispiel für die Verwendung leerer Funktionen geben?

  3. Oder gibt es eine Tradition von Programmiersprachen, die leere Funktionen zulassen?


EDIT (Dinge, die ich durch das Lesen Ihrer Antworten erhalten habe):

  • Zum Skizzieren von Algorithmen oder mit abstrakten Funktionen
  • Zum Senden von Formularen muss keine Aktion ausgeführt werden
  • Platzhalter für einige obligatorische Operationen
Jeyanthinath
quelle
1
Sie können als STUBS verwendet werden, wenn die Programmausführung erwartet, sie zu finden / zu verwenden, Sie jedoch nichts durch sie ändern möchten.
G.Rassovsky

Antworten:

5

In Shell-Sprachen der Bourne-Familie wird der :Befehl, der überhaupt nichts tut, normalerweise in zwei Situationen verwendet:

  • Platzhalter für den Fall, dass etwas einen obligatorischen Befehl erwartet, z

    while some_condtion
    do :
    done
    

    da doerfordert mindestens einen Befehl.

  • Verwerfen der Argumente, aber Ausführen von Nebenwirkungen innerhalb der Argumentliste, z

    : ${myvar=foo}

Ich bin sicher, dass es wahrscheinlich andere Anwendungen gibt, die Shell-Experten kennen würden :)

In Python (und anderen Sprachen) wird es weniger häufig verwendet. Es kann als Argument für eine Funktion höherer Ordnung dienen, wenn Sie eigentlich nichts tun möchten. Angenommen, Sie haben eine Funktion, die ein Formular sendet und ermöglicht, dass eine Funktion nach Abschluss der Übermittlung asynchron aufgerufen wird:

def submit(callback=empty_func):
    ...

Auf diese Weise wird callbackdie Übermittlung weiterhin durchgeführt , wenn dies nicht bereitgestellt wird, es werden jedoch keine weiteren Aktionen ausgeführt. Wenn Sie Noneals Standardwert verwendet haben, müssen Sie explizit prüfen, ob der Rückruf erfolgt ist None, und dem Code Unordnung hinzufügen.

Rüschenwind
quelle
1

Es hängt davon ab, wo Sie sich im Entwicklungszyklus befinden. Manchmal möchten Sie jedoch beim Skizzieren eines Algorithmus eine Abstraktion über komplexe Blöcke vornehmen, ohne diese sofort zu implementieren.

def full_algo():
  init_stuff()
  process_stuff()
  ...

Sie wissen, wie init_stuffes funktionieren wird, es ist ziemlich einfach in Ihrem Kopf, aber Sie brauchen es nicht sofort, also deklarieren Sie es als leere Funktion. Dadurch kann Ihr Code kompiliert und ausgeführt werden, ohne sich um die wichtigsten Details zu kümmern.

Eine andere Verwendung für freigegebene Anwendungen ist die Verwendung der Vererbung. Angenommen, Sie haben eine große Klasse, die das Verhalten von plattformspezifischem Code definiert. Möglicherweise erhalten Sie eine ähnliche Logik:

init_filesystem();
access_files();
release_filesystem();

Dieser Code funktioniert auf vielen Plattformen, aber einige Plattformen benötigen möglicherweise keine Dateisysteminitialisierung. Dann sieht Ihre Vererbung folgendermaßen aus (virtuell mit = 0 in C ++ bedeutet nur, dass abgeleitete Klassen diese Methoden implementieren MÜSSEN):

class FileSystem{
  virtual void init_filesystem() = 0;
  virtual void access_files() = 0;
  virtual void release_filesystem() = 0;
};

Dann kann eine bestimmte Implementierung dieser Klasse (Schnittstelle) für einige dieser Methoden nichts bewirken. Alternativ könnte die Basisklasse leere Methoden für init / release deklarieren, anstatt sie als virtuell zu deklarieren.

Schließlich (und schändlicherweise) pflegen Sie manchmal eine sehr alte Anwendung. Sie befürchten, dass das Löschen von Methoden zu Problemen führen kann. Dies geschieht, wenn Sie eine komplexe Vererbung haben, die nicht richtig verstanden wird, oder wenn Sie viele Funktionszeiger (Rückrufe) haben. Sie löschen einfach den Code in ihnen, damit sie trotzdem aufgerufen werden, ohne etwas zu beschädigen.

Eric
quelle
0

Rufflewind hat gute Arbeit geleistet, wenn Sie eine leere Funktion in einem abgeschlossenen Programm verwenden könnten. Nach meiner Erfahrung wird es in unvollendeten Programmen häufiger verwendet, sodass Sie planen können, was Sie schreiben möchten, und es noch kompilieren können, bis Sie mit der tatsächlichen Implementierung beginnen. Mit anderen Worten, es ist normalerweise nur ein Platzhalter.

In Pythons Fall ist dies erforderlich, da im Gegensatz zu C-ähnlichen Sprachen, die geschweifte Klammern verwenden, Einrückungen zum Markieren von Blöcken verwendet werden {}. Das heißt, wenn Sie nicht hatten pass, konnte der Parser nicht sagen, ob Sie es leer lassen wollten oder ob Sie es vergessen haben. Das Einschließen passvereinfacht den Parser erheblich und gibt Ihnen ein bequemes Wort, nach dem Sie suchen können, wenn Sie nach nicht implementierten Blöcken suchen.

Karl Bielefeldt
quelle
1
Für unfertigen Code ist das Werfen NotImplementedErroreine adäquatere Lösung, da "Fehler niemals stillschweigend passieren sollten" und das Aufrufen einer nicht implementierten Funktion in einem Live-Programm ein Fehler ist.
ivan_pozdeev
Das hängt davon ab. Für Code, den Sie versenden, ja. Wenn es sich jedoch um Code handelt, den Sie voraussichtlich in einer Stunde implementieren werden und den Sie während der Arbeit an den Komponententests nur nicht implementieren, ist es möglicherweise besser, keine Implementierung zu belassen. Oft ist mein Workflow 1) Schreibstub-Methode mit pass 2) Schreibeinheitentest, der den Rückgabewert testet 3) Überprüfungstest schlägt fehl (da die Methode undefiniert zurückgibt) 4) Implementierungsmethode 5) Überprüfungstest jetzt bestanden
Gort the Robot
0

Während dies in Python nicht zu erwarten ist, gibt es in der Welt der Gerätetreiber Zeiten, in denen Sie eine leere Funktion bereitstellen müssen, um ein Ereignis zu behandeln, von dem Sie entweder (a) wissen, dass es nicht eintreten wird oder ( b) kümmert sich nicht darum, auch wenn es so ist.

Sie sehen dies auch in C mit Rückrufen. Gelegentlich wird Code angezeigt, der davon ausgeht, dass Sie einen Rückruf angegeben haben, und versucht, ihn aufzurufen, wobei das Risiko eines Nullzeigers ignoriert wird. In diesem Fall können Sie lediglich eine leere Rückrufroutine angeben. (Ja, ich habe einen bestimmten Anbieter im Sinn.)

John R. Strohm
quelle
Ich habe passviel als Platzhalter beim Schreiben von Code verwendet, insbesondere in Klassen, wenn ich etwas ausführen möchte, bevor alles vollständig ist. Es ist wirklich das Äquivalent von {}Python, was Python nicht kann, da es keine geschweiften Klammern verwendet. In diesem Sinne erlauben alle Sprachen, die mir bekannt sind, dies, nur dass nur ein paar wie pythonein Schlüsselwort benötigen. Schon in den Montagetagen hatten wir NOP.
Gort the Robot
@StevenBurnap, normalerweise, wenn ich so etwas mache, füge ich das lokale Äquivalent von printf hinzu (">>> Routine XXX namens \ n");
John R. Strohm