Как только обработать *args и * * kwargs в decorator и оставить другие аргументы нетронутыми


Я хочу иметь декоратор, который принимает только *args и **kwargs в качестве входных данных, вносит в них некоторые изменения и затем вызывает исходную функцию с позиционными и именованными аргументами из оформленной функции без изменений.

Изменение аргументов состоит в том, чтобы просто добавить -- к args, а также к ключам dict из kwargs.

Например, я хочу использовать этот декоратор следующим образом:
from decorator import decorator

@decorator
def prepare_opts(decorated_func, *args, **kwargs):
    prepared_args = prepare_single_opt_keys(args)
    prepared_kwargs = prepare_named_opt_keys(kwargs)

    return decorated_func(*prepared_args, **prepared_kwargs)

@my_decorator
def func1(pos1, pos2, *args, named1=None, **kwargs):
    ...do stuff

Здесь pos1, pos2 и named1 должны быть проигнорированы оформитель.

Итак, вызов func1 Такой:

func1('foo', 'bar', 'foo', 'bar', named1='foobar', foo='bar')

Следует вызывать декорированную функцию следующим образом:

func1('foo', 'bar', named1='foobar', ('--foo', '--bar'), {'--foo': 'bar'})
Но это, очевидно, не может работать, так как декоратор переходит от ('--foo', '--bar', '--foo', '--bar') к pos1 и {'--named1': 'foobar', '--foo': 'bar'} к pos2.

Я знаю, что смогу получить правильные аргументы, если изменю декоратор на:

@decorator
def prepare_opts(decorated_func, pos1, pos2, *args, named1, **kwargs):
    prepared_args = prepare_single_opt_keys(args)
    prepared_kwargs = prepare_named_opt_keys(kwargs)

    return decorated_func(pos1, pos2, *prepared_args, named1, **prepared_kwargs)
Но проблема здесь в том, что я хочу, чтобы декоратор работал с большим количеством различных функций, которые все имеют разное количество позиционных и именованных параметры и дополнительные *args и **kwargs.

Резюме моего вопроса: есть ли способ проанализировать *args и **kwargs в декораторе, не касаясь ни одного из позиционных и именованных аргументов декорированной функции и не потребляя их в *args/**kwargs-Аргументы моей декораторской функции?

1 2

1 ответ:

Вы можете попробовать проверить.getargspec функция. Я не проверял его, но вы можете использовать этот подход.

import inspect

def your_decorator(func):
    func_args = inspect.getargspec(func)[0]
    args_number = len(func_args)

    def wrapper(*args, **kwargs):
        if len(args) > args_number:
            args[args_number:] = prepare_single_opt_keys(args[args_number:])
        optional_kwargs = {k: kwargs.pop(k) for k in kwargs if k not in func_args}
        prepared_kwargs = prepare_named_opt_keys(optional_kwargs)
        kwargs.update(prepared_kwargs)
        return func(*args, **kwargs)
    return wrapper
Но я совершенно уверен, что вам это не нужно. Такого рода самоанализа следует и почти всегда можно избежать.