【问题标题】:Decorating a function to create a class that splits keyword and positional arguments into two other methods装饰一个函数以创建一个将关键字和位置参数拆分为其他两个方法的类
【发布时间】:2025-12-29 19:45:17
【问题描述】:

我有一个抽象类 @abstractmethods 它的 __init____call__。原则上,类定义是这样的:

class Base(abc.ABC):
    @abc.abstractmethod
    def __init__(self, **params):
        pass

    @abc.abstractmethod
    def __call__(self, *input):
        pass

我想创建一个装饰器,将函数的关键字参数转换为__init__ 的参数,并将位置参数转换为__call__:所以如果

def func(a, b, *args, k=1, g=2, **kwargs):
    pass # it does something

然后我想将我的 func 包装在一个装饰器中,该装饰器将像以下行一样输出

class Func(Base):
    def __init__(self, k=1, g=2, **kwargs):
        inspected_kwargs = ... # arguments of init in dictionary form
        for argname, val in inspected_kwargs.items():
             setattr(self, argname, val)

    def __call__(self, a, b, *args):
        inspected_args = ... # arguments of call in tuple form
        return func(*inspected_args, **self.__dict__)

我曾尝试使用inspect,但我不确定如何将inspect.Signature 对象的参数注入回以创建函数。另外,我遇​​到了一些麻烦,因为当将本地方法添加到具有简单属性设置的函数内部的类时,返回该类时本地函数不再在范围内。

问题是:如何在函数内部创建一个类,其方法是基于函数输入可调用的签名定义的?

@编辑 要提供有关该想法的更多详细信息:

def decorator(function):
    class Inner(Base):
        pass
    # non-existent functions ahead, just to convey the idea
    # the exact way to do this is exactly the matter of this question
    sig = inspect.get_signature(function)
    init = create_from_signature(signature=sig.keyword_arguments(),
body="for name, val in sig.keyword_arguments():\nsetattr(self, name, val)")
    call = create_from_signature(signature=sig.positional(),
body="return partial(func, **self.__dict__)")
    Inner.__init__ = init
    Inner.__call__ = call
    # it would be nice if Inner class name would also depend on
    # func name:
    setattr(Inner, __name__, "_".join(function.__name__, "decorated"))
    return Inner

def users_function(a, b, k=5):
    # user's code; does whatever, for me it's a black box
    return a * b / k

预期行为:

decorator(users_function)(k=10)(1, 2) == users_function(1, 2, k=10)

我为什么要这样做?因为这样就可以在输出的对象上调用Base 的方法,只需要知道关键字参数:

my_obj = decorator(users_function)(k=10)
my_obj.basemethod() # basemethod is implementd in Base class

【问题讨论】:

  • 不确定我是否完全理解,您能否澄清您的最后一点。另外,您到底在哪里遇到问题?谢谢。
  • 我只是不知道如何创建一个匹配来自签名对象的签名的函数。稍后将此方法添加到类中是另一个问题。

标签: python python-decorators inspect


【解决方案1】:

我正试图准确了解您的问题,所以让我们从这个例子开始:

def decorator(function):

    def wrapper(*args, **kwargs):

        print(' [decorator] Printing before function [' + function.__name__ + '] execution')

        result = function(*args, **kwargs)

        print(' [decorator] Found args: ' + str(args))
        print(' [decorator] Found kwargs: ' + str(kwargs))

        print(' [decorator] Printing after function [' + function.__name__ + '] execution')

        return result

    return wrapper


@decorator
def MyFunction(*args, **kwargs):

    print('[MyFunction] Received args:' + str(args))
    print('[MyFunction] Received kwargs:' + str(kwargs))


MyFunction(1, 2, kwarg1=3, kwarg2=2)

这将导致:

 [decorator] Printing before function [MyFunction] execution
[MyFunction] Received args:(1, 2)
[MyFunction] Received kwargs:{'kwarg1': 3, 'kwarg2': 2}
 [decorator] Found args: (1, 2)
 [decorator] Found kwargs: {'kwarg1': 3, 'kwarg2': 2}
 [decorator] Printing after function [MyFunction] execution

您需要从哪里解决问题?

【讨论】: