Wywołanie funkcji modułu za pomocą jego nazwy (ciąg znaków)

Jaki jest najlepszy sposób na wywołanie funkcji w programie Pythona. Na przykład, załóżmy, że mam moduł foo i mam ciąg znaków, którego zawartość to "bar". Jaki jest najlepszy sposób na wywołanie foo.bar()?

Muszę uzyskać wartość zwracaną funkcji, dlatego nie używam tylko eval. Wymyśliłem, jak to zrobić, używając eval do zdefiniowania funkcji temp, która zwraca wynik wywołania tej funkcji, ale mam nadzieję, że jest na to bardziej elegancki sposób.

 1244
Author: Claus Wilke, 2008-08-06

10 answers

Zakładając Moduł foo z metodą bar:

import foo
method_to_call = getattr(foo, 'bar')
result = method_to_call()

Jeśli chodzi o to, Linie 2 i 3 mogą być skompresowane do:

result = getattr(foo, 'bar')()

Jeśli to ma sens dla Twojego przypadku użycia. Możesz używać getattr w ten sposób na metodach związanych z instancjami klasy, metodach na poziomie modułów, metodach klas... lista jest długa.

 1510
Author: Patrick Johnmeyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-22 18:10:17
locals()["myfunction"]()

Lub

globals()["myfunction"]()

Locals zwraca słownik z bieżącą tabelą symboli lokalnych. globals zwraca słownik z globalną tabelą symboli.

 414
Author: sastanin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-07 12:45:13

Rozwiązanie Patricka jest chyba najczystsze. Jeśli chcesz dynamicznie podnieść moduł, możesz zaimportować go w następujący sposób:

module = __import__('foo')
func = getattr(module, 'bar')
func()
 253
Author: HS.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-22 18:08:23

Zwykły wkład. Jeśli klasa, którą musimy instancjonować, znajduje się w tym samym pliku, możemy użyć czegoś takiego:

# 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()

Na przykład:

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')

I, jeśli nie klasa:

def sampleFunc(arg):
    print('you called sampleFunc({})'.format(arg))

globals()['sampleFunc']('sample arg')
 86
Author: Sourcegeek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-22 21:49:18

Biorąc pod uwagę ciąg znaków, z pełną ścieżką Pythona do funkcji, oto jak zacząłem uzyskiwać wynik wspomnianej funkcji:

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()
 67
Author: ferrouswheel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-16 00:24:22

Odpowiedź (mam nadzieję) nikt nigdy nie chciał

Eval like behavior

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

Dlaczego nie dodać auto-Import

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

W przypadku, gdy mamy dodatkowe słowniki chcemy sprawdzić

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

Musimy wejść głębiej

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")()
 33
Author: 00500005,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-09 10:17:41

Najlepszą odpowiedzią według Python programming FAQ byłoby:

functions = {'myfoo': foo.bar}

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

Podstawową zaletą tej techniki jest to, że łańcuchy nie muszą pasować do nazw funkcji. Jest to również podstawowa technika używana do emulowania konstrukcji przypadku

 30
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-24 13:20:46

Jeśli chcesz przekazać nazwę funkcji (lub klasy) i nazwę aplikacji jako łańcuch znaków, możesz to zrobić:

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)
 19
Author: trubliphone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-14 05:55:36

Nic z tego, co sugerowano, mi nie pomogło. Jednak odkryłem to.

<object>.__getattribute__(<string name>)(<params>)

Używam Pythona 2.66

Hope this helps

 15
Author: Natdrip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-28 16:56:45

Spróbuj tego. Chociaż nadal używa eval, używa go tylko do przywołania funkcji z bieżącego kontekstu . Następnie masz prawdziwą funkcję do użycia, jak chcesz.

Główną korzyścią dla mnie z tego jest to, że otrzymasz wszelkie błędy związane z eval w momencie wywołania funkcji. Wtedy otrzymasz tylko błędy związane z funkcją podczas wywoływania.

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)
 14
Author: tvt173,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-08 18:09:50