2009-07-09 9 views
9

Sto scrivendo estensioni C, e mi piacerebbe rendere visibile la firma dei miei metodi per l'introspezione.Estensione Python C: firme dei metodi per la documentazione?

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

Ora, se (dopo costruirlo ...) che carico il modulo e guardo il suo aiuto:

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

mi metterò:

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. 

Mi piacerebbe essere ancora più specifico ed essere in grado di sostituire foo (...) di foo (timeout, flags = None)

Posso fare questo? Come?

risposta

6

Il mio approccio abituale per scoprire cose come questa è: "usa la fonte".

Fondamentalmente, presumevo che i moduli standard di python usassero tale funzionalità quando disponibili. Guardare la fonte (for example here) dovrebbe aiutare, ma in realtà anche i moduli standard aggiungono il prototipo dopo l'uscita automatica. Come questo:

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

Quindi, come a monte non sta usando una tale funzione, vorrei assumere che non c'è. :-)

OK, ho appena controllato i sorgenti attuali di python3k e questo è ancora il caso. Tale firma viene generata in pydoc.py nelle origini python qui: pydoc.py. Rilevante stralcio di partenza in linea 1260:

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

inspect.isfunction verifica se l'oggetto della documentazione è richiesta per è una funzione Python. Ma le funzioni implementate da C sono considerate integrate, quindi otterrai sempre name(...) come output.

3

È stato 7 anni ma è possibile includere la firma per la funzione di estensione C e le classi.

Python utilizza lo Argument Clinic per generare dinamicamente le firme. Quindi alcuni meccanismi creano uno __text_signature__ e questo può essere introspettato (ad esempio con help). @MartijnPieters ha spiegato questo processo abbastanza bene in this answer.

Si può effettivamente ottenere la clinica argomento in pitone e di farlo in modo dinamico, ma io preferisco il modo manuale: Aggiunta della firma al docstring:

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

I fatto un uso pesante di questo nel mio pacchetto: iteration_utilities/src. Quindi, per dimostrare che funziona uso una delle funzioni C-estensione esposti da questo pacchetto:

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

Il docstring per questa funzione è definita this file.

E 'importante rendersi conto che questo non è possibile per Python 3.4 < ed è necessario seguire alcune regole:

  • è necessario includere --\n\n dopo la linea di definizione di firma.

  • La firma deve essere nella prima riga della docstring.

  • La firma deve essere valida, ovvero foo(a, b=1, c) non riesce perché non è possibile definire argomenti posizionali dopo gli argomenti con valore predefinito.

  • È possibile fornire solo una firma. Così non funziona se si utilizza qualcosa come:

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

Fa questo lavoro con 'inspect.signature'? – Eric

+0

@Eric Sì, a condizione che segua le regole di '__text_signature__' di cui sopra. – MSeifert

+0

Sembra una cosa che 'numpy' ha bisogno di una patch per – Eric

Problemi correlati