Python元编程:生成带有类型注释的函数签名

Che*_*evy 3 python metaprogramming type-hinting

我正在使用 Python 3 类型注释进行验证和依赖注入的 Python Web 框架内工作。

所以我正在寻找一种方法来从给定生成函数的参数中生成带有类型注释的函数:

def gen_fn(args: Dict[str, Any]) -> Callable:
    def new_fn(???):
        pass
    return new_fn
Run Code Online (Sandbox Code Playgroud)

以便

inspect.signature(gen_fn({'a': int}))
Run Code Online (Sandbox Code Playgroud)

将返回

<Signature (a:int)>
Run Code Online (Sandbox Code Playgroud)

有什么我可以放的东西而不是???可以做我需要的东西。

我也看着Signature.replace()了在inspect模块,但没有找到一种方法,新的签名附加到新的或现有的功能。

我对使用ast犹豫不决,因为:

抽象语法本身可能会随着每个 Python 版本而改变

所以我的问题是:基于传递给生成函数的a 生成带有 Python 3 类型注释的函数的合理方法什么(如果有的话)dict


编辑:虽然@Aran-Fey解决方案正确回答了我的问题,但我的假设似乎是错误的。更改签名不允许new_fn使用新签名调用。那就是gen_fn({'a': int})(a=42)引发了TypeError:......`得到了一个意外的关键字参数'a'。

Ara*_*Fey 7

与创建带有注释的函数相比,创建函数然后手动设置注释更容易。

将它们放在一起:

def gen_fn(args: Dict[str, Any]) -> Callable:
    def new_fn():
        pass

    params = [inspect.Parameter(param,
                                inspect.Parameter.POSITIONAL_OR_KEYWORD,
                                annotation=type_)
                            for param, type_ in args.items()]
    new_fn.__signature__ = inspect.Signature(params)
    new_fn.__annotations__ = args

    return new_fn

print(inspect.signature(gen_fn({'a': int})))  # (a:int)
print(get_type_hints(gen_fn({'a': int})))  # {'a': <class 'int'>}
Run Code Online (Sandbox Code Playgroud)

请注意,这不会使您的函数可以使用这些参数调用;所有这些都只是使函数看起来像是有那些参数和注释的雾里看花。实现该功能是一个单独的问题。

您可以使用varargs定义函数以将所有参数聚合到一个元组和一个 dict 中:

def new_fn(*args, **kwargs):
    ...
Run Code Online (Sandbox Code Playgroud)

但这仍然给您带来了实现函数体的问题。你还没有说函数被调用时应该做什么,所以我不能帮你。您可以查看此问题以获取一些提示。