Вызов функции модуля по его имени (строке)
Как вызвать функцию, используя строку с именем функции? Например:
import foo
func_name = "bar"
call(foo, func_name) # должно вызвать foo.bar()
Мне нужно знать, как реализовать такой вызов функции в Python.
5 ответ(ов)
Конечно! Вот перевод вашего ответа на русский язык в стиле 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() # Вызываем функцию и сохраняем результат
Таким образом, вы сможете динамически загружать и вызывать функции из различных модулей.
Вопрос: Как реализовать поведение, аналогичное 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 и аналогичных методов может привести к потере читаемости кода и увеличивает вероятность ошибок. Поэтому всегда важно тщательно обдумывать, стоит ли так усложнять реализацию ваших функций.
Попробуйте это. Хотя здесь всё еще используется eval, он применяется лишь для получения функции из текущего контекста. После этого у вас есть реальная функция, которую вы можете использовать по своему усмотрению.
Основное преимущество для меня в этом заключается в том, что вы получите любые ошибки, связанные с eval, в момент получения функции. Затем, когда вы вызовете функцию, вы получите только ошибки, связанные с самой функцией.
def say_hello(name):
print 'Hello {}!'.format(name)
# получаем функцию по имени
method_name = 'say_hello'
method = eval(method_name)
# вызываем её как обычную функцию позже
args = ['friend']
kwargs = {}
method(*args, **kwargs)
На всякий случай, если вам нужно передать имя функции (или класса) и имя приложения в виде строки, то вы можете сделать это следующим образом:
myFnName = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn = getattr(app, myFnName)
Этот код загружает модуль приложения по имени и получает ссылку на функцию по её имени из строки.
К сожалению, ни одно из предложений мне не помогло. Однако я обнаружил вот что:
<object>.__getattribute__(<string name>)(<params>)
Я использую Python 2.6.6
Надеюсь, это поможет.
Как преобразовать вложенный словарь Python в объект?
В чем разница между __init__ и __call__?
Класс Classname(object): что такое 'object' в Python?
Полностью завернуть объект в Python
"_set" в объекте queryset в Django