Создание functools.partial * args & * kwargs из проанализированных строк - PullRequest
1 голос
/ 13 октября 2010

Мне передают списки строк, которые я хотел бы преобразовать в вызовы методов, используя functools.partial:

[ 'object1.method1(arg1, arg2, 4, key=value)', 'object2.method2(6, arg1)' ...]

Легко использовать регулярное выражение для генерации необходимого аргумента 'func' для functools.частично, но у меня дьявольское время, когда я легко конвертирую строку в скобках в действительные * args и ** kwargs для передачи в functools.partial.

Каждый элемент списка гарантированно будет действительным Python.Я просто не могу придумать быстрый и простой способ конвертировать строки, такие как 'arg1, arg2, 4, key = value', в нечто, что может использовать functools.partial.Чего мне не хватает?

Обновление:

Мои извинения.Я забыл жизненно важную информацию.Аргументы не являются допустимыми идентификаторами в рамках этой процедуры, поэтому 'eval' не работает.Однако они верны в области, в которой будут использоваться результирующие частичные объекты, поэтому их можно «копировать» как литералы.Моя текущая процедура возвращает строку «arg1, arg2, 4, this = that».Если передать непосредственно в functools.partial, functools.partial «оборачивает» его в один строковый аргумент.

Хммм ... чем больше я это описываю, тем больше понимаю, что нет способа сделать это, если только эти идентификаторыдействительны в этой области ...

Ответы [ 2 ]

2 голосов
/ 14 октября 2010

Я пишу другой ответ, потому что, если я изменю старый, комментарии вообще не будут отражать содержание. Вместо этого, если это окажется лучшим ответом, я отзову другой. Следующее должно работать.

Теория работы:

  1. Получи свой функционал
  2. рассекать строку для аргументов
  3. положить каждый аргумент вместе с его собственным eval в частичном
  4. помещает обертку, func и частичные аргументы в частичный
  5. выполнить в необходимом объеме

Следующий код концентрируется на 2.-4. Импорт предполагается. Конечно, существует дополнительная проблема столкновения имен из-за дополнительного кода в области видимости


def wrapper(func_, *args, **kw):
    new_args = []
    new_kw = {}
    for arg in args:
        if type(arg)==functools.partial:
            arg = arg()
        new_args.append(arg)
    for key in kw:
        value = kw[key]
        if type(value)==functools.partial:
            value = value()
        new_kw[key]=value
     return func_(*new_args, **new_kw)

orig_str = 'object1.method1(arg1, arg2, 4, key=value)'
argstr = re.search('.+\((.+)\)', orig_str).group(1)
args = []
kw = {}
for x in argstr.split(','):
    if '=' in x:
        key, value = x.strip().split('=')
    else:
        value = x.strip()
        key = None            
    value = functools.partial(eval, value)
    if key:
        kw[key]=value
    else:
        args.append(value)

what_you_want = functools.partial(wrapper, func, *args, **kw)
0 голосов
/ 20 августа 2015

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

def get_args_and_kwargs(*args, **kwargs):
    return args, kwargs

def convert_str_to_args_and_kwargs(s):
    return eval(s.replace(s[:s.find('(')], 'get_args_and_kwargs'))

for s in your_list:
    args, kwargs = convert_str_to_args_and_kwargs(s)
...