2396 Stimmen

Aufruf einer Funktion eines Moduls mit Hilfe seines Namens (einer Zeichenkette)

Was ist der beste Weg, um eine Funktion aufzurufen, wenn man eine Zeichenkette mit dem Namen der Funktion in einem Python-Programm hat. Nehmen wir zum Beispiel an, dass ich ein Modul habe foo und ich habe eine Zeichenkette mit folgendem Inhalt "bar" . Wie kann ich am besten anrufen? foo.bar() ?

Ich muss den Rückgabewert der Funktion erhalten, weshalb ich nicht einfach eval . Ich habe herausgefunden, wie man das macht, indem man eval um eine temporäre Funktion zu definieren, die das Ergebnis dieses Funktionsaufrufs zurückgibt, aber ich hoffe, dass es einen eleganteren Weg gibt, dies zu tun.

8 Stimmen

Die Verwendung von eval würde wahrscheinlich einige Sicherheitsbedenken aufwerfen!

23 Stimmen

Zu Ihrer Information: Das Sprachmerkmal des Zugriffs auf Felder, Klassen und Methoden durch dynamische Namen heißt Reflexion . Das könnte die künftige Suche erleichtern.

88voto

Die beste Antwort ist nach Ansicht der Python-Programmierung FAQ wäre:

functions = {'myfoo': foo.bar}

mystring = 'myfoo'
if mystring in functions:
    functions[mystring]()

Der Hauptvorteil dieser Technik ist, dass die Zeichenketten nicht mit den Namen der Funktionen übereinstimmen müssen. Dies ist auch die primäre Technik, um ein Case-Konstrukt zu emulieren

72voto

00500005 Punkte 3297

Die Antwort, die (hoffentlich) niemand wollte

Verhalten wie bei Eval

getattr(locals().get("foo") or globals().get("foo"), "bar")()

Warum nicht automatisch importieren

getattr(
    locals().get("foo") or 
    globals().get("foo") or
    __import__("foo"), 
"bar")()

Falls wir zusätzliche Wörterbücher haben, die wir prüfen wollen

getattr(next((x for x in (f("foo") for f in 
                          [locals().get, globals().get, 
                           self.__dict__.get, __import__]) 
              if x)),
"bar")()

Wir müssen tiefer gehen

getattr(next((x for x in (f("foo") for f in 
              ([locals().get, globals().get, self.__dict__.get] +
               [d.get for d in (list(dd.values()) for dd in 
                                [locals(),globals(),self.__dict__]
                                if isinstance(dd,dict))
                if isinstance(d,dict)] + 
               [__import__])) 
        if x)),
"bar")()

26 Stimmen

Dies könnte durch rekursives Scannen des Verzeichnisbaums und automatisches Einbinden von USB-Laufwerken verbessert werden

1 Stimmen

Das ist definitiv die Antwort, die ich wollte. Perfekt.

46voto

tvt173 Punkte 1558

Versuchen Sie dies. Dies verwendet zwar immer noch eval, aber nur, um die Funktion aus dem aktuellen Kontext aufzurufen . Dann haben Sie die eigentliche Funktion, die Sie nach Belieben nutzen können.

Der Hauptvorteil besteht für mich darin, dass Sie alle eval-bezogenen Fehler bereits beim Aufruf der Funktion erhalten. Dann erhalten Sie nur die funktionsbezogenen Fehler beim Aufruf.

def say_hello(name):
    print 'Hello {}!'.format(name)

# get the function by name
method_name = 'say_hello'
method = eval(method_name)

# call it like a regular function later
args = ['friend']
kwargs = {}
method(*args, **kwargs)

3 Stimmen

Das wäre riskant. string kann alles Mögliche enthalten, und eval würde es am Ende ohne Rücksicht auswerten.

7 Stimmen

Sicherlich müssen Sie darauf achten, in welchem Kontext Sie es verwenden, ob es angesichts dieser Risiken angemessen ist oder nicht.

6 Stimmen

Eine Funktion sollte nicht für die Validierung ihrer Parameter verantwortlich sein - das ist die Aufgabe einer anderen Funktion. Die Aussage, dass es riskant ist, eval mit einer Zeichenkette zu verwenden, bedeutet, dass die Verwendung jeder Funktion riskant ist.

43voto

trubliphone Punkte 3649

Wenn Sie den Namen der Funktion (oder Klasse) und den Namen der Anwendung als Zeichenkette übergeben müssten, könnten Sie dies tun:

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)

2 Stimmen

Nur etwas allgemeiner ist handler = getattr(sys.modules[__name__], myFnName)

1 Stimmen

Wie funktioniert es, wenn die Funktion eine Klassenfunktion ist?

21voto

Serjik Punkte 9789

Da diese Frage Dynamischer Aufruf von Methoden innerhalb einer Klasse durch Zuweisung eines Methodennamens an eine Variable [duplizieren] als Duplikat markiert, poste ich hier eine verwandte Antwort:

Das Szenario ist, eine Methode in einer Klasse wollen eine andere Methode auf der gleichen Klasse dynamisch aufrufen, habe ich einige Details zu ursprünglichen Beispiel, das einige weitere Szenario und Klarheit bietet hinzugefügt:

class MyClass:
    def __init__(self, i):
        self.i = i

    def get(self):
        func = getattr(MyClass, 'function{}'.format(self.i))
        func(self, 12)   # This one will work
        # self.func(12)    # But this does NOT work.

    def function1(self, p1):
        print('function1: {}'.format(p1))
        # do other stuff

    def function2(self, p1):
        print('function2: {}'.format(p1))
        # do other stuff

if __name__ == "__main__":
    class1 = MyClass(1)
    class1.get()
    class2 = MyClass(2)
    class2.get()

Ausgabe (Python 3.7.x)

Funktion1: 12

Funktion2: 12

1 Stimmen

Tolle Antwort, danke :) Ich habe den gleichen Ansatz versucht, bin aber gescheitert, weil ich nicht wusste, dass ich "self" wieder in den eigentlichen Funktionsaufruf aufnehmen muss. Haben Sie eine Erklärung dafür, warum dies notwendig ist?

1 Stimmen

Meine beste Vermutung: obj.method in Python ruft tatsächlich method(self, ...) auf, im Falle von getattr konnte dieser synthetische Zucker vom Python-Interpreter nicht angewendet werden.

2 Stimmen

Der Punkt ist die Verwendung von Klassennamen anstelle von "self" im getattr-Befehl. Ich habe versucht, getattr(self, key)() zu verwenden, und es gab den Fehler, dass int nicht aufrufbar ist, aber als ich es in "getattr(HomeScreen, key)(self)" geändert habe, funktioniert es jetzt. "HomeScreen" ist übrigens ein Klassenname...danke...

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X