- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
假设我有一个自定义装饰器,我希望它能够正确处理装饰函数的文档字符串。问题是:我的装饰器添加了一个参数。
from functools import wraps
def custom_decorator(f):
@wraps(f)
def wrapper(arg, need_to_do_more):
'''
:param need_to_do_more: if True: do more
'''
args = do_something(arg)
if need_to_do_more:
args = do_more(args)
return f(args)
return wrapper
你可以看到参数实际上并没有传递给装饰函数,而是被包装器使用——这可能是也可能是在这里不相关。
如何正确处理记录附加参数?包装器采用额外参数是一种好习惯,还是我应该避免它?
或者我应该使用不同的解决方案,例如:
最佳答案
所以 - __doc__
除了这很棘手 - 而且,由于越来越多的开发人员在编码时依赖自动参数建议,这是由 IDE 自省(introspection)提供的,任何装饰器都确实需要它将向函数添加额外的命名参数。
我在 a project I am developing 中做到了这一点,解决方案是创建一个新的虚拟函数,它将显示所需的组合签名 - 然后使用这个新的虚拟函数作为 @wraps
调用的参数,。
这是我的代码 - 它已经足够好了,因此与其他项目无关,我可能很快就会将它放入装饰器 Python 包中。现在:
def combine_signatures(func, wrapper=None):
"""Adds keyword-only parameters from wrapper to signature
Use this in place of `functools.wraps`
It works by creating a dummy function with the attrs of func, but with
extra, KEYWORD_ONLY parameters from 'wrapper'.
To be used in decorators that add new keyword parameters as
the "__wrapped__"
Usage:
def decorator(func):
@combine_signatures(func)
def wrapper(*args, new_parameter=None, **kwargs):
...
return func(*args, **kwargs)
"""
# TODO: move this into 'extradeco' independent package
from functools import partial, wraps
from inspect import signature, _empty as insp_empty, _ParameterKind as ParKind
from itertools import groupby
if wrapper is None:
return partial(combine_signatures, func)
sig_func = signature(func)
sig_wrapper = signature(wrapper)
pars_func = {group:list(params) for group, params in groupby(sig_func.parameters.values(), key=lambda p: p.kind)}
pars_wrapper = {group:list(params) for group, params in groupby(sig_wrapper.parameters.values(), key=lambda p: p.kind)}
def render_annotation(p):
return f"{':' + (repr(p.annotation) if not isinstance(p.annotation, type) else repr(p.annotation.__name__)) if p.annotation != insp_empty else ''}"
def render_params(p):
return f"{'=' + repr(p.default) if p.default != insp_empty else ''}"
def render_by_kind(groups, key):
parameters = groups.get(key, [])
return [f"{p.name}{render_annotation(p)}{render_params(p)}" for p in parameters]
pos_only = render_by_kind(pars_func, ParKind.POSITIONAL_ONLY)
pos_or_keyword = render_by_kind(pars_func, ParKind.POSITIONAL_OR_KEYWORD)
var_positional = [p for p in pars_func.get(ParKind.VAR_POSITIONAL,[])]
keyword_only = render_by_kind(pars_func, ParKind.KEYWORD_ONLY)
var_keyword = [p for p in pars_func.get(ParKind.VAR_KEYWORD,[])]
extra_parameters = render_by_kind(pars_wrapper, ParKind.KEYWORD_ONLY)
def opt(seq, value=None):
return ([value] if value else [', '.join(seq)]) if seq else []
annotations = func.__annotations__.copy()
for parameter in pars_wrapper.get(ParKind.KEYWORD_ONLY):
annotations[parameter.name] = parameter.annotation
param_spec = ', '.join([
*opt(pos_only),
*opt(pos_only, '/'),
*opt(pos_or_keyword),
*opt(keyword_only or extra_parameters, ('*' if not var_positional else f"*{var_positional[0].name}")),
*opt(keyword_only),
*opt(extra_parameters),
*opt(var_keyword, f"**{var_keyword[0].name}" if var_keyword else "")
])
declaration = f"def {func.__name__}({param_spec}): pass"
f_globals = func.__globals__
f_locals = {}
exec(declaration, f_globals, f_locals)
result = f_locals[func.__name__]
result.__qualname__ = func.__qualname__
result.__doc__ = func.__doc__
result.__annotations__ = annotations
return wraps(result)(wrapper)
在交互模式下测试得到这样的结果:
IPython 7.8.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from terminedia.utils import combine_signatures
In [2]: def add_color(func):
...: @combine_signatures(func)
...: def wrapper(*args, color=None, **kwargs):
...: global context
...: context.color = color
...: return func(*args, **kw)
...: return wrapper
...:
In [3]: @add_color
...: def line(p1, p2):
...: pass
...:
In [4]: line
Out[4]: <function __main__.line(p1, p2, *, color=None)>
(至于 doc 字符串,就像问题中一样 - 一旦获得了所有包装器和函数数据,这是粘贴之前的文本处理问题 result.__doc__ = func.__doc__
。因为每个项目在 docstrings 中都有不同的文档参数样式,它不能以“一刀切”的方式可靠地完成,但是通过一些字符串拼接和测试,它可以针对任何给定的文档字符串样式进行完善)
关于python - 签名更 retrofit 饰器 : properly documenting additional argument,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34402773/
作为一个小项目(没有什么关键任务),我决定尝试用 C# 编写 GOST 28147-89 的实现。但是,在阅读 RFC 5830 时(定义 GOST 28147-89 的信息),我注意到了这一点。 (
我在 Android JNI 上使用 Neon 实现了一个算法。当我想将向量相加时,我注意到有两种类型的方法,但我看不出其中的区别。 // pairwise addition int8x8_t vpa
我想知道为什么 STL 没有重载它们的算法函数,这样我就可以通过简单地提供一个容器而不是采用更冗长的方式来传递开始 + 结束迭代器来调用它们。我当然理解为什么我们还想使用迭代器对来处理容器/数组的子序
我想知道为什么 STL 不会重载它们的算法函数,这样我就可以通过简单地提供一个容器而不是采用更冗长的方式来传递 begin + end 迭代器来调用它们。我当然理解为什么我们还想使用迭代器对来处理容器
假设我有两个模块 - Module1、Module2。 每个模块在 Visual Studio 中都有自己的项目。 如何使用“附加模块依赖项”或“附加 BMI 目录”设置将模块 2 导入模块 1? 问
我有一个问题 df = data.frame(col1 = c("A", "B", "C", "A", "A", "B"), col2 = c(0.2, 0.2, 0.6, 1, 0.8, 0.2),
在sencha touch中,我有一个如下声明的轮播: ajaxNav = new Ext.Panel({ scroll: 'vertical', cls: 'card1 dem
我有一个开始日期,如下所示: var beginDate = "29/04/2015"; var beginHour = "13:32"; 我有一些持续时间变量: var hourDuration =
我一直在以一种相当粗糙的函数式方式进行一些动态系统模拟,目前正试图弄清楚 cpp 对象可以为我的代码带来什么。更具体地说,我在考虑以下结构: 我想通过一个抽象类来指定动力系统,比如“DynSys”,用
我想知道是否有办法强制将图像加载为 8U。我在 OpenCV 文档中看到您可以指定是将图像加载为单 channel 还是三 channel ,但没有提及颜色深度。有什么建议吗? 感谢您的帮助!!! :
题目地址:https://leetcode.com/problems/additive-number/description/ 题目描述: Additive number is a string
我已经使用 react-leaflet 有一段时间了,几周后我删除了 node_modules 中的文件并重新安装了它们,我根本没有接触 react-leaflet 版本,但是当我尝试运行时该项目,它
令我惊讶的是,我发现在 TCanvas 上重复渲染文本在某种程度上是“附加的”。我意识到设置 Canvas.Brush.Style:=bsClear 是问题的原因,但我确实需要透明且重复地渲染文本(即
我有一个 pdf 文件,其中包含“UniCNS-UCS2-H”字体,我尝试了 pdfbox 和 pdfrenderer,它们都抛出异常:“UniCNS-UCS2-H”的未知编码 这个字体包含在一个字体
我有一个大多数用户只会使用一次的 Facebook 应用程序。在进入 Facebook 工作流程之前,用户表明他们是否希望自己的墙被写入。基于此,我要么请求 publish_stream 许可,要么不
我正在尝试使用 CodeIgnitor 在 php、mysql 中制作标记表。我已经使用XAMPP并创建了一个数据库。用于存储每条记录。正在从数据库中检索数据,插入的新记录已成功编辑 但问题在于检索总
是否可以为 AppStore 应用审核提供额外的文件? 我们正在开发一个与 SAP 服务器通信的应用程序。为了审查该应用程序,我们设置了一个可供 Apple 访问的测试服务器。但是该服务器上的证书是自
enter image description here 我正在尝试设置我的函数并执行一些重载操作,以便我可以 +、-、==、* 两个矩阵。我在第一次操作重载时遇到了一个问题:加法。 我的程序一直有效
我正在尝试制作一个可以执行各种算术函数的基本计算器,从加法开始!现在我已经弄清楚了它的基本逻辑,但我不确定如何获取两个输入并将其打印出来! #include int main() { cha
这个问题在这里已经有了答案: Showing a Windows form on a secondary monitor? (9 个回答) 关闭 9 年前。 我有一个应用程序,其中有一个我想在第二个
我是一名优秀的程序员,十分优秀!