Jaki jest najlepszy sposób na wywołanie funkcji, biorąc pod uwagę ciąg z nazwą funkcji w programie Python. Na przykład, powiedzmy, że mam moduł foo i mam ciąg, którego treści jest "bar". Jaki jest najlepszy sposób na zadzwonić foo.bar()?

Muszę uzyskać wartość powrotową funkcji, dlatego nie tylko używam eval. Wskazałem na to, jak to zrobić za pomocą eval, aby zdefiniować funkcję TEMP, która zwraca wynik tego połączenia funkcji, ale mam nadzieję, że istnieje bardziej elegancki sposób na to.

2104
ricree 6 sierpień 2008, 07:36

12 odpowiedzi

Najlepsza odpowiedź

Zakładając moduł foo z metodą {X1}}:

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

Możesz skrócić linie 2 i 3 do:

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

Jeśli to ma więcej sensu dla twojego przypadku użycia.

Możesz użyć

Boris 9 październik 2019, 20:24

Rozwiązanie Patricka jest prawdopodobnie najczystsze. Jeśli musisz również dynamicznie odebrać moduł, możesz zaimportować go jak:

module = __import__('foo')
func = getattr(module, 'bar')
func()
364
Ben Hoyt 22 luty 2017, 18:08

Tylko prosty wkład. Jeśli klasa musimy wystał, jest 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')

A jeśli nie klasa:

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

globals()['sampleFunc']('sample arg')
125
tbc0 22 wrzesień 2014, 21:49

Biorąc pod uwagę ciąg, z kompletną ścieżką Python do funkcji, tak poszedłem na uzyskanie wyniku 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()
115
ferrouswheel 16 październik 2013, 00:24

Najlepsza odpowiedź według Python Programming FAQ byłby:

functions = {'myfoo': foo.bar}

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

Podstawową zaletą tej techniki jest to, że łańcuchy nie muszą odpowiadać nazwy funkcji. Jest to również podstawowa technika używana do emulacji konstruktów przypadków

64
user3946687user3946687 24 październik 2016, 13:20

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

Eval jak zachowanie

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

Dlaczego nie dodać auto-importowania

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

W przypadku, gdy mamy dodatkowe słowniki, które 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 zejść 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")()
48
00500005 9 kwiecień 2014, 10:17

Warto, jeśli warto przekazać nazwę funkcji (lub klasy) i nazwę aplikacji jako łańcucha, możesz to zrobić:

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)
28
trubliphone 14 luty 2012, 05:55

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

Główną korzyścią dla mnie jest, że otrzymasz błędy związane z evalem w punkcie przywołania funkcji. Następnie otrzymasz tylko błędy związane z plikiem , gdy zadzwonisz.

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)
24
tvt173 8 grudzień 2016, 18:09

Żaden z tego, co zasugerowało mi pomogło. Odkryłem to jednak.

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

Używam Pythona 2.66

Mam nadzieję że to pomoże

13
Natdrip 28 grudzień 2012, 16:56

Jak to pytanie W jaki sposób Aby dynamicznie połączyć metody w klasie przy użyciu przypisania metody nazwy do zmiennej [duplikat] oznaczone jako duplikat jako ten, publikuję tutaj powiązaną odpowiedź:

Scenariusz jest metodą w klasie, który chce zadzwonić do innej metody na tej samej klasie dynamicznie, dodałem pewne szczegóły do oryginalnego przykładu, który oferuje pewne szersze scenariusz i jasność:

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

Wyjście (Python 3.7.x)

Funkcja1: 12.

Funkcja2: 12.

8
Serjik 19 kwiecień 2019, 20:51

Jest to prosta odpowiedź, pozwoli Ci na przykład usunąć ekran. Istnieją dwa przykłady poniżej, z Eval i Exec, które będą drukować 0 na górze po czyszczeniu (jeśli używasz okien, zmień clear do cls, Linux i Mac Użytkownicy zostawiają, jak na przykład ) lub tylko wykonaj go odpowiednio.

eval("os.system(\"clear\")")
exec("os.system(\"clear\")")
-10
Number File 28 sierpień 2019, 16:46