2009-07-09 8 views
9

J'écris des extensions C, et j'aimerais rendre visible la signature de mes méthodes pour l'introspection.Extension Python C: signatures de méthodes pour la documentation?

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"); 
} 

Maintenant, si (après sa construction ...) je charge le module et regarde son aide:

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

je vais obtenir:

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. 

Je voudrais être encore plus spécifique et être en mesure de remplacer foo (...) par foo (timeout, flags = None)

Puis-je faire ceci? Comment?

Répondre

6

Mon approche habituelle pour trouver des choses comme ceci est: "utiliser la source". Fondamentalement, je présume que les modules standard de python utiliseraient une telle fonctionnalité lorsqu'elle serait disponible. Regarder la source (for example here) devrait aider, mais en fait même les modules standards ajoutent le prototype après la sortie automatique. Comme ceci:

[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 [...] 

Alors que l'amont n'utilise pas une telle fonctionnalité, je suppose qu'il n'y est pas. :-)

Bon, je viens de vérifier les sources python3k actuelles et c'est toujours le cas. Cette signature est générée dans pydoc.py dans les sources python ici: pydoc.py. départ extrait pertinent en ligne 1260:

 
     if inspect.isfunction(object): 
      args, varargs, varkw, defaults = inspect.getargspec(object) 
      ... 
     else: 
      argspec = '(...)' 

vérifie inspect.isfunction si l'objet de la documentation est demandée pour est une fonction Python. Mais les fonctions implémentées en C sont considérées comme des builtins, donc vous obtiendrez toujours name(...) comme sortie.

3

Il a été 7 ans mais vous pouvez inclure la signature pour la fonction C-extension et les classes.

Python lui-même utilise le Argument Clinic pour générer dynamiquement des signatures. Ensuite, certains mécaniciens créent un __text_signature__ et cela peut être introspecté (par exemple avec help). @MartijnPieters a très bien expliqué ce processus en this answer.

Vous pouvez réellement obtenir la clinique argument de python et de le faire d'une manière dynamique, mais je préfère la façon manuelle: Ajout de la signature au docstring:

Dans votre cas:

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."); 

I fait un usage intensif de ceci dans mon paquet: iteration_utilities/src. Donc, pour démontrer que cela fonctionne-je utiliser une des fonctions C-extension exposées par ce paquet:

>>> 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. 
[...] 

Le docstring pour cette fonction est définie this file.

Il est important de se rendre compte que ce est impossible pour python < 3.4 et vous devez suivre quelques règles:

  • Vous devez inclure --\n\n après la ligne de définition de signature.

  • La signature doit être dans la première ligne de la docstring.

  • La signature doit être valide, c'est-à-dire foo(a, b=1, c) échoue car il n'est pas possible de définir des arguments positionnels après les arguments par défaut.

  • Vous ne pouvez fournir qu'une seule signature. Donc, il ne fonctionne pas si vous utilisez quelque chose comme:

    foo(a) 
    foo(x, a, b) 
    -- 
    
    Narrative documentation 
    
+0

Est-ce que ce travail avec 'inspect.signature'? – Eric

+0

@Eric Oui, tant qu'il suit les règles de '__text_signature__' mentionnées ci-dessus. – MSeifert

+0

Cela ressemble à une chose que «numpy» a besoin d'un correctif pour – Eric

Questions connexes