Вызов функции модуля по его имени (строке)
Как вызвать функцию, используя строку с именем функции? Например:
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 наследуют от object?
Сохранить график в файл изображения вместо его отображения
Преобразование списка словарей в DataFrame pandas
Как использовать десятичное значение шага в range()?
Как отсортировать список/кортеж списков/кортежей по элементу на заданном индексе