Расширение Python C: подписи методов для документации?
Я пишу 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 (...) на foo (timeout, flags = None)
Могу ли я это сделать? Как?
Ответы
Ответ 1
Мой обычный подход к выяснению таких вещей: "использовать источник".
В принципе, я бы предположил, что стандартные модули python будут использовать такую функцию, когда она будет доступна. Если посмотреть на источник (например, здесь), это должно помочь, но на самом деле даже стандартные модули добавляют прототип после автоматического выхода. Вот так:
[email protected]:~$ python2.6
>>> import fcntl
>>> help(fcntl.flock)
flock(...)
flock(fd, operation)
Perform the lock operation op on file descriptor fd. See the Unix [...]
Так как восходящий поток не использует такую функцию, я бы предположил, что ее нет.: -)
Хорошо, я только что проверил текущие источники python3k, и это все еще так. Эта подпись генерируется в pydoc.py
в источниках python: pydoc.py. Соответствующая выдержка, начинающаяся в строке 1260:
if inspect.isfunction(object):
args, varargs, varkw, defaults = inspect.getargspec(object)
...
else:
argspec = '(...)'
inspect.isfunction проверяет, является ли объект, к которому запрашивается документация, является функцией Python. Но C реализованные функции считаются встроенными, поэтому вы всегда получите name(...)
в качестве вывода.
Ответ 2
Прошло 7 лет , но вы можете включить подпись для функции расширения C и классов.
Сам Python использует Argument Clinic для динамического создания подписей. Затем некоторые механики создают __text_signature__
, и это может быть интродуцировано (например, с помощью help
). @MartijnPieters очень хорошо объяснили этот процесс в этом ответе.
Фактически вы можете получить аргумент клиники из python и сделать это динамически, но я предпочитаю ручной способ: добавление подписи в docstring:
В вашем случае:
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.
[...]
Docstring для этой функции определяется этот файл.
Важно понимать, что этот невозможен для python < 3.4, и вам нужно соблюдать некоторые правила:
-
Вам нужно включить --\n\n
после строки определения подписи.
-
Подпись должна быть в первой строке docstring.
-
Подпись должна быть действительной, т.е. foo(a, b=1, c)
терпит неудачу, потому что невозможно определить позиционные аргументы после аргументов по умолчанию.
-
Вы можете предоставить только одну подпись. Таким образом, это не работает, если вы используете что-то вроде:
foo(a)
foo(x, a, b)
--
Narrative documentation