Aufrufen einer Funktion eines Moduls mithilfe seines Namens (einer Zeichenfolge)
Frage
Was ist der beste Weg, um eine Funktion aufzurufen, wenn in einem Python-Programm eine Zeichenfolge mit dem Namen der Funktion vorhanden ist?Nehmen wir zum Beispiel an, ich habe ein Modul foo
, und ich habe eine Zeichenfolge, deren Inhalt ist "bar"
.Wie rufe ich am besten an? foo.bar()
?
Ich muss den Rückgabewert der Funktion erhalten, weshalb ich sie nicht einfach verwende eval
.Ich habe mithilfe von herausgefunden, wie es geht eval
Ich möchte eine temporäre Funktion definieren, die das Ergebnis dieses Funktionsaufrufs zurückgibt, aber ich hoffe, dass es eine elegantere Möglichkeit gibt, dies zu tun.
Lösung
Angenommenes Modul foo
mit Methode bar
:
import foo
method_to_call = getattr(foo, 'bar')
result = method_to_call()
Soweit das geht, können die Zeilen 2 und 3 wie folgt komprimiert werden:
result = getattr(foo, 'bar')()
wenn das für Ihren Anwendungsfall sinnvoller ist.Sie können verwenden getattr
auf diese Weise auf Klasseninstanz-gebundene Methoden, Methoden auf Modulebene, Klassenmethoden ...Die Liste geht weiter.
Andere Tipps
locals()["myfunction"]()
oder
globals()["myfunction"]()
Einheimische gibt ein Wörterbuch mit einer aktuellen lokalen Symboltabelle zurück. Globale gibt ein Wörterbuch mit globaler Symboltabelle zurück.
Patricks Lösung ist wahrscheinlich die sauberste.Wenn Sie das Modul auch dynamisch abrufen müssen, können Sie es wie folgt importieren:
module = __import__('foo')
func = getattr(module, 'bar')
func()
Nur ein einfacher Beitrag.Wenn sich die Klasse, die wir instanziieren müssen, in derselben Datei befindet, können wir so etwas verwenden:
# Get class from globals and create an instance
m = globals()['our_class']()
# Get the function (from the instance) that we need to call
func = getattr(m, 'function_name')
# Call it
func()
Zum Beispiel:
class A:
def __init__(self):
pass
def sampleFunc(self, arg):
print('you called sampleFunc({})'.format(arg))
m = globals()['A']()
func = getattr(m, 'sampleFunc')
func('sample arg')
# Sample, all on one line
getattr(globals()['A'](), 'sampleFunc')('sample arg')
Und wenn keine Klasse:
def sampleFunc(arg):
print('you called sampleFunc({})'.format(arg))
globals()['sampleFunc']('sample arg')
Bei einer gegebenen Zeichenfolge mit einem vollständigen Python-Pfad zu einer Funktion habe ich folgendermaßen vorgegangen, um das Ergebnis dieser Funktion zu erhalten:
import importlib
function_string = 'mypackage.mymodule.myfunc'
mod_name, func_name = function_string.rsplit('.',1)
mod = importlib.import_module(mod_name)
func = getattr(mod, func_name)
result = func()
Die beste Antwort laut der Häufig gestellte Fragen zur Python-Programmierung wäre:
functions = {'myfoo': foo.bar}
mystring = 'myfoo'
if mystring in functions:
functions[mystring]()
Der Hauptvorteil dieser Technik besteht darin, dass die Zeichenfolgen nicht mit den Namen der Funktionen übereinstimmen müssen.Dies ist auch die primäre Technik, die zur Emulation eines Fallkonstrukts verwendet wird
Die Antwort (hoffe ich) wollte niemand jemals
Bewertungsähnliches Verhalten
getattr(locals().get("foo") or globals().get("foo"), "bar")()
Warum nicht den automatischen Import hinzufügen?
getattr(
locals().get("foo") or
globals().get("foo") or
__import__("foo"),
"bar")()
Falls wir zusätzliche Wörterbücher haben, die wir überprüfen möchten
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")()
Wenn Sie den Funktions- (oder Klassen-)Namen und den App-Namen als Zeichenfolge übergeben müssen, können Sie Folgendes tun:
myFnName = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn = getattr(app,myFnName)
Versuche dies.Dies verwendet zwar immer noch eval, aber nur dazu Rufen Sie die Funktion aus dem aktuellen Kontext auf.Dann haben Sie die eigentliche Funktion, die Sie nach Ihren Wünschen nutzen können.
Für mich besteht der Hauptvorteil darin, dass Sie beim Aufrufen der Funktion alle evaluierungsbezogenen Fehler erhalten.Dann wirst du bekommen nur die funktionsbedingten 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)
Nichts von dem, was vorgeschlagen wurde, hat mir geholfen.Ich habe das allerdings entdeckt.
<object>.__getattribute__(<string name>)(<params>)
Ich verwende Python 2.66
Hoffe das hilft
Wie diese Frage So rufen Sie Methoden innerhalb einer Klasse dynamisch auf, indem Sie den Methodennamen einer Variablen zuweisen [Duplikat] Als Duplikat wie dieses markiert, poste ich hier eine entsprechende Antwort:
Das Szenario sieht so aus, dass eine Methode in einer Klasse eine andere Methode derselben Klasse dynamisch aufrufen möchte. Ich habe dem ursprünglichen Beispiel einige Details hinzugefügt, die ein umfassenderes Szenario und Klarheit bieten:
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