HOWTO · Python

Funktionsaufruf aus String-Name in Python

Es wird demonstriert, wie man eine Funktion aus einer Zeichenkette in Python aufruft

Auf dieser Seite

Wenn ein Funktionsname als Zeichenkette vorliegt, suchen Sie ihn in einer bewusst festgelegten Menge erlaubter Funktionen und rufen Sie das gefundene Funktionsobjekt auf. Für Befehle oder andere vom Benutzer ausgewählte Aktionen ist ein Dictionary meist die klarste Wahl: Es macht die verfügbaren Namen sichtbar und verhindert, dass beliebige Eingaben nicht vorgesehene Funktionen auswählen.

Ein Dictionary verwenden, um freigegebene Namen Funktionen zuzuordnen

Definieren Sie die Funktionen wie gewohnt und ordnen Sie dann die zulässigen Zeichenketten den Funktionsobjekten zu. Suchen Sie den angeforderten Namen und prüfen Sie vor dem Aufruf, ob das Ergebnis aufrufbar ist. Dieses Beispiel behandelt einen unbekannten Namen, ohne einen Aufruf zu versuchen:

Der bereitgestellte Lauf hat dieses eigenständige Beispiel mit Exitcode 0 abgeschlossen und 8 ausgegeben. Führen Sie es so aus:

Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.

def add(left, right):
    return left + right


def multiply(left, right):
    return left * right


functions = {"add": add, "multiply": multiply}
name = "add"
function = functions.get(name)

if callable(function):
    print(function(5, 3))
else:
    print(f"Unknown function: {name}")
8

Die Zuordnung ist eine Allowlist: Auswählbar sind nur Namen, die Sie zu functions hinzufügen. Verwenden Sie .get(), wenn ein fehlender Name eine erwartbare Eingabe ist, und legen Sie fest, wie die Anwendung einen unbekannten Namen melden oder behandeln soll. Wenn die Funktionen unterschiedliche Argumente erwarten, prüfen Sie auch die Argumente für die ausgewählte Aktion. Eine erfolgreiche Namenssuche garantiert nicht, dass die Aufrufsignatur stimmt.

getattr() verwenden, um ein Attribut eines Objekts oder Moduls abzurufen

Verwenden Sie getattr(object, name, default), wenn die Zeichenkette ein Attribut eines bestimmten Objekts oder Moduls auswählen soll. Das dritte Argument liefert einen Wert, wenn das Attribut nicht vorhanden ist. Prüfen Sie anschließend, ob der Wert aufrufbar ist: Ein vorhandenes Attribut kann auch Daten statt einer Funktion enthalten.

Der bereitgestellte Lauf hat dieses Beispiel mit Exitcode 0 abgeschlossen und 8 ausgegeben. Es ruft eine gebundene Instanzmethode ab: Python bindet calculator an die Methode, daher übergeben Sie nur deren übrige Argumente. Führen Sie es so aus:

Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.

class Calculator:
    def add(self, left, right):
        return left + right


calculator = Calculator()
name = "add"
operation = getattr(calculator, name, None)

if callable(operation):
    print(operation(5, 3))
else:
    print(f"No callable attribute named {name}")
8

Dasselbe Muster funktioniert mit einem Modulobjekt, zum Beispiel mit getattr(math, name, None) nach dem Import von math. Das Abrufen einer Instanzmethode über die Instanz liefert eine gebundene Methode; beim Abrufen über die Klasse erhalten Sie die ungebundene Funktion und müssen die Instanz als Argument übergeben. Beschränken Sie das Quellobjekt und die erlaubten Attributnamen, wenn die Zeichenkette von außerhalb Ihres Codes stammt.

globals() und locals() nur verwenden, wenn der Namensraum bewusst gewählt ist

globals() liefert den globalen Namensraum des aktuellen Moduls zurück. Die Funktion liefert keine lokalen Variablen zurück. Eine globale Suche kann nützlich sein, wenn die Funktionen bewusst in diesem Modul definiert sind. Der bereitgestellte Lauf hat dieses Beispiel mit Exitcode 0 abgeschlossen und 8 ausgegeben. Führen Sie es so aus:

Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.

def add(left, right):
    return left + right


name = "add"
function = globals().get(name)

if callable(function):
    print(function(5, 3))
else:
    print(f"Unknown global function: {name}")
8

locals() bezieht sich auf den lokalen Namensraum an der Stelle, an der die Funktion aufgerufen wird. Innerhalb einer Funktion kann sie dort lokale Namen verfügbar machen; sie untersucht weder die lokalen Variablen der aufrufenden Funktion noch durchsucht sie das Programm allgemein. Ihr Verhalten hängt vom Gültigkeitsbereich ab. Deshalb ist sie als Dispatcher meist weniger klar und weniger geeignet als eine explizite Zuordnung. Weitere Informationen zu Dictionaries finden Sie im Python-Tutorial zu Dictionaries.

Warum eval() für die Funktionssuche riskant ist

eval() wertet einen Python-Ausdruck aus, statt lediglich einen freigegebenen Funktionsnamen nachzuschlagen. Beispielsweise analysiert und wertet eval("add(5, 3)") einen Aufrufausdruck aus und verwendet dabei die Namen, die in seiner Auswertungsumgebung verfügbar sind. Enthält ein Ausdruck nicht vertrauenswürdige Eingaben, kann seine Auswertung Code mit den Berechtigungen des Python-Prozesses ausführen. Verwenden Sie eval() nicht, um Namen aus Benutzereingaben, Dateien, Netzwerkanfragen oder anderen nicht vertrauenswürdigen Quellen aufzurufen.

Wenn ein Ausdruck tatsächlich aus einer vertrauenswürdigen, kontrollierten Quelle stammt, dokumentiert Python das Verhalten und die Parameter für den Namensraum von eval(). Für die gewöhnliche Auswahl einer Funktion ist eine Dictionary-Allowlist einfacher und begrenzt, was die Eingabe auswählen kann. Text zu analysieren oder zu validieren macht die beliebige Auswertung nicht zu einem sicheren Ersatz für eine ausdrücklich festgelegte Auswahl an Aktionen.

Die Suchmethode passend zur Eingabe auswählen

Verwenden Sie ein Dictionary, wenn die verfügbaren Aktionen ausdrücklich festgelegt sein sollen, besonders bei Namen aus Benutzereingaben oder externen Quellen. Verwenden Sie getattr(), wenn das Objekt oder Modul bereits feststeht und die Zeichenkette eines seiner Attribute auswählen soll; prüfen Sie den Standardwert und die Aufrufbarkeit und berücksichtigen Sie die Methodenbindung. Verwenden Sie globals() nur, wenn eine Suche auf Modulebene beabsichtigt ist. Verwenden Sie locals() nur, wenn der Code bewusst Namen im aktuellen lokalen Gültigkeitsbereich benötigt, nicht als allgemeinen Dispatcher. Verwenden Sie eval() nicht zur Namenssuche, wenn die Eingabe nicht vollständig vertrauenswürdig ist.

In jedem Fall sind Suche und Aufruf getrennte Entscheidungen: Begrenzen Sie zuerst, welche aufrufbare Funktion ausgewählt werden kann, und übergeben Sie dann Argumente, die zu ihrer Schnittstelle passen. Bei einer festen Auswahl an Befehlen lässt sich das Verhalten so leichter prüfen und warten.