15

我正在编写 C 扩展,我想让我的方法的签名可见以进行自省。

static PyObject* foo(PyObject *self, PyObject *args) {

    /* blabla [...] */

}

PyDoc_STRVAR(
    foo_doc,
    "Great example function\n"
    "Arguments: (timeout, flags=None)\n"
    "Doc blahblah doc doc doc.");

static PyMethodDef methods[] = {
    {"foo", foo, METH_VARARGS, foo_doc},
    {NULL},
};

PyMODINIT_FUNC init_myexample(void) {
    (void) Py_InitModule3("_myexample", methods, "a simple example module");
}

现在如果(在构建它之后......)我加载模块并查看它的帮助:

>>> import _myexample
>>> help(_myexample)

我会得到:

Help on module _myexample:

NAME
    _myexample - a simple example module

FILE
    /path/to/module/_myexample.so

FUNCTIONS
    foo(...)
        Great example function
        Arguments: (timeout, flags=None)
        Doc blahblah doc doc doc.

我想更具体一点,并且能够用foo (timeout, flags=None)替换foo(... )

我可以这样做吗?如何?

4

2 回答 2

16

已经 7 年了,但您可以包含 C-extension function 和 classes 的签名

Python 本身使用Argument Clinic动态生成签名。然后一些机制创建 a__text_signature__并且可以自省(例如使用help)。@MartijnPieters 在这个答案中很好地解释了这个过程。

您实际上可以从 python 获取参数诊所并以动态方式进行操作,但我更喜欢手动方式:将签名添加到文档字符串:

在你的情况下:

PyDoc_STRVAR(
    foo_doc,
    "foo(timeout, flags=None, /)\n"
    "--\n"
    "\n"
    "Great example function\n"
    "Arguments: (timeout, flags=None)\n"
    "Doc blahblah doc doc doc.");

我在我的包中大量使用了这个:iteration_utilities/src. 因此,为了证明它有效,我使用了此包公开的 C 扩展函数之一:

>>> from iteration_utilities import minmax
>>> help(minmax)
Help on built-in function minmax in module iteration_utilities._cfuncs:

minmax(iterable, /, key, default)
    Computes the minimum and maximum values in one-pass using only
    ``1.5*len(iterable)`` comparisons. Recipe based on the snippet
    of Raymond Hettinger ([0]_) but significantly modified.

    Parameters
    ----------
    iterable : iterable
        The `iterable` for which to calculate the minimum and maximum.
[...]

此函数的文档字符串在此文件中定义。

重要的是要意识到这对于 python < 3.4 是不可能的,您需要遵循一些规则:

  • 您需要--\n\n在签名定义行之后包含。

  • 签名必须在文档字符串的第一行。

  • 签名必须有效,即foo(a, b=1, c)失败,因为不可能在默认参数之后定义位置参数。

  • 您只能提供一个签名。因此,如果您使用以下内容,它将不起作用:

    foo(a)
    foo(x, a, b)
    --
    
    Narrative documentation
    
于 2016-12-20T15:09:08.713 回答
6

我通常的查找此类事情的方法是:“使用源代码”。

基本上,我认为 python 的标准模块会在可用时使用这样的功能。查看源代码(例如这里)应该会有所帮助,但实际上即使是标准模块也会在自动输出之后添加原型。像这样:

torsten@pulsar:~$ python2.6
>>> 导入 fcntl
>>> 帮助(fcntl.flock)
群(...)
    羊群(fd,操作)

    对文件描述符 fd 执行锁定操作 op。参见 Unix [...]

因此,由于上游没有使用这样的功能,我会假设它不存在。:-)

好的,我刚刚检查了当前的 python3k 源,情况仍然如此。该签名在pydoc.py此处的 python 源代码中生成:pydoc.py。从第 1260 行开始的相关摘录:

        如果检查.isfunction(对象):
            参数,可变参数,varkw,默认值 = inspect.getargspec(object)
            ...
        别的:
            argspec = '(...)'

inspect.isfunction 检查请求文档的对象是否是 Python 函数。但是 C 实现的函数被视为内置函数,因此您将始终得到name(...)输出。

于 2009-07-09T16:11:30.060 回答