gpt4 book ai didi

python - 将带有注释的签名添加到扩展方法

转载 作者:太空宇宙 更新时间:2023-11-03 11:16:37 25 4
gpt4 key购买 nike

在我的应用程序中嵌入 Python 并编写扩展类型时,我可以添加 signature使用精心制作的 .tp_doc字符串。

static PyMethodDef Answer_methods[] = {
{ "ultimate", (PyCFunction)Answer_ultimate, METH_VARARGS,
"ultimate(self, question='Life, the universe, everything!')\n"
"--\n"
"\n"
"Return the ultimate answer to the given question." },
{ NULL }
};

help(Answer)执行后,返回以下内容(略):
class Answer(builtins.object)
|
| ultimate(self, question='Life, the universe, everything!')
| Return the ultimate answer to the given question.

这很好,但我使用的是 Python3.6,它支持注释。我想将问题注释为字符串,以及返回 int 的函数。我试过了:
static PyMethodDef Answer_methods[] = {
{ "ultimate", (PyCFunction)Answer_is_ultimate, METH_VARARGS,
"ultimate(self, question:str='Life, the universe, everything!') -> int\n"
"--\n"
"\n"
"Return the ultimate answer to the given question." },
{ NULL }
};

但这会恢复到 (...)符号,文档变为:
 |  ultimate(...)
| ultimate(self, question:str='Life, the universe, everything!') -> int
| --
|
| Return the ultimate answer to the given question.

并要求 inspect.signature(Answer.ultimate)导致异常。
Traceback (most recent call last):
File "<string>", line 11, in <module>
File "inspect.py", line 3037, in signature
File "inspect.py", line 2787, in from_callable
File "inspect.py", line 2266, in _signature_from_callable
File "inspect.py", line 2090, in _signature_from_builtin
ValueError: no signature found for builtin <built-in method ultimate of example.Answer object at 0x000002179F3A11B0>

我已经尝试使用 Python 代码在事后添加注释:
example.Answer.ultimate.__annotations__ = {'return': bool}

但是内置方法描述符不能以这种方式添加注释。
Traceback (most recent call last):
File "<string>", line 2, in <module>
AttributeError: 'method_descriptor' object has no attribute '__annotations__'

有没有办法使用 C-API 向扩展方法添加注释?

Argument Clinic 看起来很有希望并且可能仍然非常有用,但从 3.6.5 开始,它 doesn't support annotations .

annotation
The annotation value for this parameter. Not currently supported, because PEP 8 mandates that the Python library may not use annotations.

最佳答案

TL;DR 目前没有办法做到这一点。

签名和 C 扩展如何协同工作?

理论上它是这样工作的(对于 Python C 扩展对象):

  • 如果 C 函数具有“正确的文档字符串”,则签名存储在 __text_signature__ 中。属性。
  • 如果您调用helpinspect.signature在这样的对象上,它会解析 __text_signature__并尝试从中构造一个签名。

  • 如果您使用参数诊所,您不需要自己编写“正确的文档字符串”。签名行是根据代码中的注释生成的。但是,前面提到的 2 个步骤仍然会发生。它们恰好发生在自动生成的签名行上。

    这就是为什么像 sum 这样的内置 Python 函数的原因。有一个 __text-signature__年代:
    >>> sum.__text_signature__
    '($module, iterable, start=0, /)'

    本例中的签名是通过基于 on the comments around the sum implementation 的参数诊所生成的。 .

    注释有什么问题?

    注解有几个问题:
  • 返回注释违反了“正确的文档字符串”的约定。所以__text_signature__添加返回注释时将为空。这是一个主要问题,因为解决方法必然涉及重写负责文档字符串的 CPython C 代码部分 -> __text_signature__翻译!这不仅复杂,而且您还必须提供更改后的 CPython 版本,以便它适用于使用您的函数的人。

    举个例子,如果你使用这个“签名”:
    ultimate(self, question:str='Life, the universe, everything!') -> int

    你得到:
    >>> ultimate.__text_signature__ is None
    True

    但是,如果您删除返回注释:
    ultimate(self, question:str='Life, the universe, everything!')

    它给你一个__text_signature__ :
    >>> ultimate.__text_signature__
    "(self, question:str='Life, the universe, everything!')"
  • 如果您没有返回注释,它仍然无法工作,因为(当前)明确不支持注释。

    假设你有这个签名:
    ultimate(self, question:str='Life, the universe, everything!')

    它不适用于 inspect.signature (异常消息实际上说明了一切):
    >>> import inspect
    >>> inspect.signature(ultimate)
    Traceback (most recent call last):
    ...
    raise ValueError("Annotations are not currently supported")
    ValueError: Annotations are not currently supported

    负责解析__text_signature__的函数是 inspect._signature_fromstr .从理论上讲,您可能可以通过对其进行猴子修补来使其工作(返回注释仍然不起作用!)。但也许不是,有几个地方对 __text_signature__ 做了假设。这可能不适用于注释。

  • PyFunction_SetAnnotations 工作?

    在评论中提到了这个 C API 函数。但是,这故意不适用于 C 扩展函数。如果您尝试在 C 扩展函数上调用它,它将引发 SystemError: bad argument to internal function call .我用一个小的 Cython Jupyter“脚本”对此进行了测试:
    %load_ext cython

    %%cython

    cdef extern from "Python.h":
    bint PyFunction_SetAnnotations(object func, dict annotations) except -1

    cpdef call_PyFunction_SetAnnotations(object func, dict annotations):
    PyFunction_SetAnnotations(func, annotations)

    >>> call_PyFunction_SetAnnotations(sum, {})

    ---------------------------------------------------------------------------
    SystemError Traceback (most recent call last)
    <ipython-input-4-120260516322> in <module>()
    ----> 1 call_PyFunction_SetAnnotations(sum, {})

    SystemError: ..\Objects\funcobject.c:211: bad argument to internal function

    所以这也不适用于 C 扩展函数。

    概括

    因此,返回注释目前完全不可能(至少在没有随程序分发您自己的 CPython 的情况下)。如果您对 inspect 中的私有(private)函数进行猴子补丁,参数注释可能会起作用。模块。这是一个 Python 模块,因此它可能是可行的,但我还没有进行概念验证,所以将其视为可能的,但可能非常复杂,几乎可以肯定不值得麻烦。

    但是,您始终可以使用 Python 函数(只是一个非常简单的包装器)包装 C 扩展函数。这个 Python 包装器可以有函数注释。它需要更多的维护和一点点慢,但可以为您省去签名和 C 扩展的所有麻烦。我不确定,但如果你使用 Cython 来包装你的 C 或 C++ 代码,它甚至可能有一些自动化工具(自动编写 Python 包装器)。

    关于python - 将带有注释的签名添加到扩展方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50537407/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com