一些没有争议的背景实验:

import inspect

def func(foo, bar):
  pass

print(inspect.signature(func))  # Prints "(foo, bar)" like you'd expect

def decorator(fn):
  def _wrapper(baz, *args, *kwargs):
    fn(*args, **kwargs)

  return _wrapper

wrapped = decorator(func)
print(inspect.signature(wrapped))  # Prints "(baz, *args, **kwargs)" which is totally understandable

问题是

如何实现我的装饰,使print(inspect.signature(wrapped))吐出"(巴,福,wine 吧)"呢?我可以通过添加传入的fn的参数,然后将baz粘贴到列表中,以某种方式动态构建_wrapper吗?

答案是否定的

def decorator(fn):
  @functools.wraps(fn)
  def _wrapper(baz, *args, *kwargs):
    fn(*args, **kwargs)

  return _wrapper

那又是"foo,bar",这完全是错误的.调用wrapped(foo=1, bar=2)是一个类型错误——"缺少1个必需的位置参数:'baz'"

我觉得没必要这么迂腐,但是

def decorator(fn):
  def _wrapper(baz, foo, bar):
    fn(foo=foo, bar=bar)

  return _wrapper

这也不是我想要的答案——我希望装饰师能够处理所有功能.

推荐答案

可以使用__signature__(PEP)属性修改包装对象的返回签名.例如:

import inspect


def func(foo, bar):
    pass


def decorator(fn):
    def _wrapper(baz, *args, **kwargs):
        fn(*args, **kwargs)

    f = inspect.getfullargspec(fn)

    fn_params = []
    if f.args:
        for a in f.args:
            fn_params.append(
                inspect.Parameter(a, inspect.Parameter.POSITIONAL_OR_KEYWORD)
            )

    if f.varargs:
        fn_params.append(
            inspect.Parameter(f.varargs, inspect.Parameter.VAR_POSITIONAL)
        )

    if f.varkw:
        fn_params.append(
            inspect.Parameter(f.varkw, inspect.Parameter.VAR_KEYWORD)
        )

    _wrapper.__signature__ = inspect.Signature(
        [
            inspect.Parameter("baz", inspect.Parameter.POSITIONAL_OR_KEYWORD),
            *fn_params,
        ]
    )
    return _wrapper


wrapped = decorator(func)
print(inspect.signature(wrapped))

输出:

(baz, foo, bar)

如果func是:

def func(foo, bar, *xxx, **yyy):
    pass

然后是print(inspect.signature(wrapped))张照片:

(baz, foo, bar, *xxx, **yyy)

Python相关问答推荐

合并与拼接并举

为什么调用函数的值和次数不同,递归在代码中是如何工作的?

pandas fill和bfill基于另一列中的条件

Django Table—如果项目是唯一的,则单行

裁剪数字.nd数组引发-ValueError:无法将空图像写入JPEG

每次查询的流通股数量

PySpark:如何最有效地读取不同列位置的多个CSV文件

浏览超过10k页获取数据,解析:欧洲搜索服务:从欧盟站点收集机会的微小刮刀&

分解polars DataFrame列而不重复其他列值

EST格式的Azure数据库笔记本中的当前时间戳

通过对列的其余部分进行采样,在Polars DataFrame中填充_null`?

如何使用aiohttp获取图像并直接处理它而不保存它?

用于从项目问题描述中提取文本的Selify代码

我的tkinter应用程序不会改变它正在加载的文件

在给定一组约束的情况下使用所有唯一组合创建数据帧

为什么我不能从我的Django views.py文件中导入通用部件?

如何在Python中删除对象

卡方检验中的不同结果

Pandas Groupby在try 聚合列时引发ValueError:LEN(索引)!=len(标签)

PyCharm调试器控制台不自动完成在调试器控制台中创建的变量