Aufrufen einer Funktion eines Moduls mithilfe seines Namens (einer Zeichenfolge)

StackOverflow https://stackoverflow.com/questions/3061

  •  08-06-2019
  •  | 
  •  

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.

War es hilfreich?

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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top