24

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

10

Как вызвать функцию, используя строку с именем функции? Например:

import foo
func_name = "bar"
call(foo, func_name)  # должно вызвать foo.bar()

Мне нужно знать, как реализовать такой вызов функции в Python.

5 ответ(ов)

1

Конечно! Вот перевод вашего ответа на русский язык в стиле StackOverflow:


Чтобы получить результат функции, используя строку с полным путём к функции, я использовал следующий подход:

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()  # Вызываем функцию и сохраняем результат

Таким образом, вы сможете динамически загружать и вызывать функции из различных модулей.

0

Вопрос: Как реализовать поведение, аналогичное eval, используя динамический доступ к переменным?

Ответ:

Надеюсь, никто никогда не хотел таких решений.

Вот базовый пример использования getattr для извлечения функции из локальной или глобальной области видимости:

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

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

0

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

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

def say_hello(name):
    print 'Hello {}!'.format(name)

# получаем функцию по имени
method_name = 'say_hello'
method = eval(method_name)

# вызываем её как обычную функцию позже
args = ['friend']
kwargs = {}
method(*args, **kwargs)
0

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

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

Этот код загружает модуль приложения по имени и получает ссылку на функцию по её имени из строки.

0

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

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

Я использую Python 2.6.6

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь