Как лучше всего вызвать функцию, заданную строкой с именем функции в программе на 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
подобным образом для методов, связанных с экземпляром класса, методов на уровне модуля, методов класса... список можно продолжить.
Решение Патрика, вероятно, самое чистое. Если вам нужно динамически подхватывать модуль, вы можете импортировать его следующим образом:
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')
Учитывая последовательность, с полным путем питона к функции, это - то, как я пошел о получении результата упомянутой функции:
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()
Лучший ответ согласно [Питон, программируя часто задаваемые вопросы] (https://docs.python.org/3/faq/programming.html#how-do-i-use-strings-to-call-functions-methods) был бы:
functions = {'myfoo': foo.bar}
mystring = 'myfoo'
if mystring in functions:
functions[mystring]()
основное преимущество этой техники состоит в том, что последовательности не должны соответствовать названиям функций. Это - также основная техника, используемая, чтобы подражать конструкции случая
Ответ (я надеюсь), никто никогда не хотел
Оценка как поведение
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")()
Поскольку, что it' s ценность, если Вы должны были передать функцию (или класс) имя и название приложения как последовательность, тогда Вы могли сделать это:
myFnName = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn = getattr(app,myFnName)
Попробуйте это. В то время как это все еще использует оценку, она только использует его для , вызывают функцию от тока context. Затем у Вас есть реальная функция, чтобы использовать, как Вы желаете.
Главная льгота для меня от этого - то, что Вы получите любые связанные с оценкой ошибки при вызове функции. Тогда Вы доберетесь только связанные с функцией ошибки, когда Вы будете звонить.
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)
Как этот вопрос Как динамично назвать методы в классе, используя назначение названия метода на переменную [дубликат] отмеченный как дубликат как этот, я публикую связанный ответ здесь:
Сценарий, метод в классе хотят назвать другой метод на том же классе динамично, я добавил некоторые детали к оригинальному примеру, который предлагает некоторый более широкий сценарий и ясность:
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()
Продукция (Пайтон 3.7.x)
function1: 12
function2: 12
Это - простой ответ, это позволит Вам очищать экран, например. Есть два примера ниже с оценкой и должностным лицом, которое напечатает 0 наверху после очистки (если you' ре используя Windows, изменитесь 'ясный' 'cls', Linux и пользователи Mac уезжают, как, например), или просто выполните его, соответственно.
eval("os.system(\"clear\")")
exec("os.system(\"clear\")")