extensão Python C: assinaturas de método para a documentação?
-
12-09-2019 - |
Pergunta
Estou escrevendo extensões C, e eu gostaria de fazer a assinatura dos meus métodos visível para a introspecção.
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");
}
Agora, se (depois de construí-la ...) eu carregar o módulo e olhar para a sua ajuda:
>>> import _myexample
>>> help(_myexample)
Vou começar:
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.
Gostaria de ser ainda mais específico e ser capaz de substituir foo (...) por foo (timeout, bandeiras = None)
Posso fazer isso? Como?
Solução
A minha abordagem usual para descobrir sobre coisas como esta é: "usar a fonte"
Basicamente, eu presumiria que os módulos padrão de python usaria esse recurso quando disponível. Olhando para a fonte ( por exemplo aqui ) deve ajudar, mas na verdade até mesmo os módulos padrão adicionar o protótipo após a saída automática. Como esta:
torsten@pulsar:~$ python2.6 >>> import fcntl >>> help(fcntl.flock) flock(...) flock(fd, operation) Perform the lock operation op on file descriptor fd. See the Unix [...]
Assim como a montante não está usando esse recurso um, eu diria que ele não está lá. : -)
Ok, eu verifiquei apenas fontes python3k atuais e esse ainda é o caso. Essa assinatura é gerada em pydoc.py
nas fontes python aqui: pydoc.py . trecho relevante a partir de linha de 1260:
if inspect.isfunction(object): args, varargs, varkw, defaults = inspect.getargspec(object) ... else: argspec = '(...)'
cheques inspect.isfunction se o objeto a documentação é solicitada para é uma função Python. Mas C implementado funções são consideradas builtins, portanto, você sempre terá name(...)
como a saída.
Outras dicas
Tem sido 7 anos , mas você pode incluir a assinatura para a função C-extensão e aulas .
próprio Python usa o Argumento Clinic para gerar dinamicamente assinaturas. Em seguida, alguns mecânicos criar um __text_signature__
e isso pode ser introspectadas (por exemplo, com help
). @MartijnPieters explicou este processo muito bem em esta resposta .
Você pode realmente começar a clínica argumento do python e fazê-lo de uma forma dinâmica, mas eu prefiro a maneira manual: Adicionando a assinatura para a docstring:
No seu caso:
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.");
Eu fiz uso pesado deste no meu pacote: iteration_utilities/src
. Então, para demonstrar que funciona eu usar uma das funções C-extensão expostos por este pacote:
>>> 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.
[...]
O docstring para esta função é definida esse arquivo .
É importante perceber que este não é possível para python <3.4 e você precisa seguir algumas regras:
-
Você precisa incluir
--\n\n
após a linha de definição de assinatura. -
A assinatura deve estar na primeira linha da docstring.
-
A assinatura deve ser válido, ou seja,
foo(a, b=1, c)
falhar porque não é possível definir argumentos posicionais após discussões com padrão. -
Você só pode fornecer uma assinatura. Então, ele não funciona se você usar algo como:
foo(a) foo(x, a, b) -- Narrative documentation