Вызов функции через строку - PullRequest
0 голосов
/ 12 июня 2019

У меня есть главная программа Python, которая импортирует другой модуль (называемый действиями) с несколькими функциями. Основная программа должна выполнить некоторые вещи, получить строку (т.е. goto (114)), а затем запустить actions.goto (114), в которой 114 является аргументом функции goto (x) в действиях.

Я попробовал очевидное, которое просто пыталось запустить строку, но это не сработало. Я также нашел метод globals (), который работал бы, если бы goto (x) был внутри моего основного модуля, и я также нашел метод getattr, но в этом случае я не нашел ни одного примера, в котором я передаю имя функции и аргумент, так что я немного потерян здесь

#main.py
import actions
def main():
    getc = 'goto(114)'
    result = actions.getc #this would be actions.goto(114)
    print result

#actions.py
def goto(x):
    #code
    return something

Фактическая программа получает строку из файла .txt, который написала другая программа, я только что сделал пример таким образом, чтобы его было легко понять.

1 Ответ

0 голосов
/ 12 июня 2019

Вы можете использовать __getattribute__ в классе action, чтобы получить функцию goto, затем вызвать ее с включающим аргументом.Вам нужно было бы проанализировать его следующим образом:

import re
import action

getc = 'goto(114)'
func, arg = re.search('(\w+)\((\d+)\)', 'goto(114)').groups()

# f is the function action.goto with the argument 114 supplied as an int
# __getattribute__ allows you to look up a class method by a string name
f = action.__getattribute__(func)

# now you can just call it with the arg converted to int
result = f(int(arg))

Регулярное выражение, возможно, нужно немного уточнить, но оно ищет имя вызывающей функции и аргументы, заключенные в скобки.__getattribute__ получит объект функции из action и вернет его без вызова, чтобы вы могли вызвать его позже.

Для нескольких аргументов вы можете использовать библиотеку ast:

import re
import ast

# I'm going to use a sample class as a stand-in
# for action
class action:
    def goto(*args):
        print(args)

getc = 'goto(114, "abc", [1,2,3])'
func, args = re.search('(\w+)\((.*)\)', getc).groups()

# will convert this into python data structures
# safely, and will fail if the argument to literal_eval
# is not a python structure
args = ast.literal_eval('(%s)' % args)

f = getattr(action, func)
f(*args)
# 114, "abc", [1,2,3]

Более простой вариант (действовать с осторожностью) будет использовать eval:

cmd = 'action.%s' % getc
result = eval(cmd)

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

...