Вызов функции модуля с использованием его имени (строки)

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

  •  08-06-2019
  •  | 
  •  

Вопрос

Каков наилучший способ вызвать функцию, учитывая строку с именем функции в программе Python?Например, предположим, что у меня есть модуль foo, и у меня есть строка , содержимое которой "bar".Каков наилучший способ позвонить foo.bar()?

Мне нужно получить возвращаемое значение функции, вот почему я не просто использую eval.Я понял, как это сделать, используя eval определить временную функцию, которая возвращает результат вызова этой функции, но я надеюсь, что есть более элегантный способ сделать это.

Это было полезно?

Решение

Предполагающий модуль foo с помощью метода bar:

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

Насколько это возможно, строки 2 и 3 могут быть сжаты до:

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

если это имеет больше смысла для вашего варианта использования.Вы можете использовать getattr таким образом, для методов, связанных с экземпляром класса, методов на уровне модуля, методов класса...этот список можно продолжать.

Другие советы

locals()["myfunction"]()

или

globals()["myfunction"]()

местные жители возвращает словарь с текущей локальной таблицей символов. глобальные переменные возвращает словарь с глобальной таблицей символов.

Решение Патрика, вероятно, самое чистое.Если вам также нужно динамически подобрать модуль, вы можете импортировать его следующим образом:

module = __import__('foo')
func = getattr(module, 'bar')
func()

Всего лишь простой вклад.Если класс, экземпляр которого нам нужен, находится в том же файле, мы можем использовать что-то вроде этого:

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

Например:

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

И, если бы не класс:

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

globals()['sampleFunc']('sample arg')

Учитывая строку с полным python-путем к функции, вот как я добился получения результата указанной функции:

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

Лучший ответ в соответствии с Питон вопросы и ответы по программированию было бы:

functions = {'myfoo': foo.bar}

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

Основное преимущество этого метода заключается в том, что строки не обязательно должны совпадать с именами функций.Это также основной метод, используемый для эмуляции конструкции case

Ответ (я надеюсь), которого никто никогда не хотел

Поведение, подобное оценке

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

Почему бы не добавить автоматический импорт

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

На случай, если у нас есть дополнительные словари, мы хотим проверить

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

Нам нужно идти глубже

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

Как бы то ни было, если вам нужно передать имя функции (или класса) и название приложения в виде строки, то вы могли бы сделать это:

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

Попробуй это.Хотя это все еще использует eval, оно использует его только для вызов функции из текущего контекста.Тогда у вас есть реальная функция, которую вы можете использовать по своему усмотрению.

Главное преимущество для меня от этого заключается в том, что вы получите любые ошибки, связанные с оценкой, в момент вызова функции.Тогда вы получите Только ошибки, связанные с функцией, при вызове.

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)

ничто из того, что было предложено, мне не помогло.Однако я действительно обнаружил это.

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

Я использую python 2.66

Надеюсь, это поможет

Поскольку этот вопрос Как динамически вызывать методы внутри класса, используя присвоение имени метода переменной [дубликат] помеченный как дубликат, как этот, я публикую соответствующий ответ здесь:

Сценарий заключается в том, что метод в классе хочет динамически вызывать другой метод в том же классе, я добавил некоторые детали к исходному примеру, который предлагает более широкий сценарий и ясность:

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

Вывод (Python 3.7.x)

функция 1:12

функция 2:12

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top