extensión de Python C: firmas de métodos para la documentación?
-
12-09-2019 - |
Pregunta
Estoy escribiendo extensiones C, y me gustaría hacer la firma de mis métodos visibles para la introspección.
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");
}
Ahora bien, si (después de su construcción ...) me carga el módulo y miro su ayuda:
>>> import _myexample
>>> help(_myexample)
voy a tener:
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.
Me gustaría ser aún más específico y ser capaz de sustituir foo (...) por foo (tiempo de espera, banderas = None)
¿Puedo hacer esto? ¿Cómo?
Solución
Mi enfoque habitual para enterarse de cosas como esta es: "usar la fuente"
.Básicamente, lo que supondría que los módulos estándar de Python usarían esta característica cuando esté disponible. En cuanto a la fuente ( por ejemplo, aquí ) debería ayudar, pero, de hecho, incluso los módulos estándar añadir el prototipo después de la salida automática. De esta manera:
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 [...]
Así como aguas arriba no está utilizando esta característica, quiero suponer que no está allí. : -)
Bueno, acabo de comprobar las fuentes python3k actuales y esto es todavía el caso. Que la firma se genera en pydoc.py
en las fuentes de pitón aquí: pydoc.py . de partida extracto relevante en la línea 1260:
if inspect.isfunction(object): args, varargs, varkw, defaults = inspect.getargspec(object) ... else: argspec = '(...)'
cheques inspect.isfunction si el objeto se solicita la documentación de es una función Python. Pero C implementa funciones se consideran órdenes internas, por lo tanto, siempre obtendrá name(...)
como la salida.
Otros consejos
Ha sido 7 años pero se puede incluir la firma de función C-extensión y clases .
sí Python utiliza el Argumento Clinic para generar dinámicamente firmas. Entonces algunos mecánicos crean una __text_signature__
y esto se puede introspección (por ejemplo, con help
). @MartijnPieters explican este proceso bastante bien en esta respuesta .
Usted puede conseguir realmente el centro de discusión de Python y hacerlo de una manera dinámica, pero yo prefiero la forma manual: Adición de la firma a la cadena de documentación:
En su 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.");
he hecho un uso intensivo de esto en mi paquete: iteration_utilities/src
. Así que para demostrar que funciona utilizo una de las funciones de extensión C-expuestos por este paquete:
>>> 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.
[...]
El docstring para esta función se define este archivo .
Es importante darse cuenta de que este no es posible para el pitón <3,4 y es necesario seguir algunas reglas:
-
Es necesario incluir
--\n\n
después de la línea de la firma definición. -
La firma debe estar en la primera línea de la cadena de documentación.
-
La firma debe ser válido, es decir
foo(a, b=1, c)
falla porque no es posible definir los argumentos posicionales después de discusiones con defecto. -
Sólo puede proporcionar una firma. Por lo tanto, no funciona si se utiliza algo como:
foo(a) foo(x, a, b) -- Narrative documentation