2009-07-09 23 views
9

Piszę rozszerzenia C i chciałbym, aby podpis moich metod był widoczny dla introspekcji.Rozszerzenie Python C: sygnatury metod dla dokumentacji?

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

Now if (po wybudowaniu go ...) I załadować moduł i spojrzeć na jego pomoc:

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

dostanę:

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. 

chciałbym być jeszcze bardziej konkretny i być w stanie zastąpić foo (...) przez foo (limit czasu, flagi = Brak)

Czy mogę to zrobić? W jaki sposób?

Odpowiedz

6

Moje zwykłe podejście do tego typu rzeczy to: "użyj źródła".

Zasadniczo przypuszczam, że standardowe moduły python będą używać takiej funkcji, gdy będą dostępne. Spojrzenie na źródło (for example here) powinno pomóc, ale w rzeczywistości nawet standardowe moduły dodają prototyp po automatycznym wyjściu. W ten sposób:

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

Tak więc, jeśli upstream nie korzysta z takiej funkcji, zakładam, że jej nie ma. :-)

Okay, właśnie sprawdziłem bieżące źródła python3k i tak jest nadal. Ten podpis jest generowany w pydoc.py w źródłach Pythona tutaj: pydoc.py. Istotny fragment początkowy w linii 1260:

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

sprawdza inspect.isfunction jeśli obiekt dokumentacja jest wymagana przez to funkcja Python. Ale zaimplementowane funkcje C są uważane za wbudowane, dlatego zawsze otrzymasz jako dane wyjściowe name(...).

3

To było 7 lat , ale można dołączyć podpis dla funkcji rozszerzenia C i klas.

Sam Python używa Argument Clinic do dynamicznego generowania podpisów. Następnie niektórzy mechanicy tworzą __text_signature__ i może to być introspekowane (na przykład z help). @MartijnPieters wyjaśnił ten proces całkiem dobrze w this answer.

można rzeczywiście dostać się do kliniki argument z pytona i zrobić to w dynamiczny sposób, ale ja wolę ręczny sposób: Dodawanie podpisu do docstring:

W twoim przypadku:

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 intensywnie korzystałem z tego w moim pakiecie: iteration_utilities/src. Tak, aby wykazać, że działa używam jedną z funkcji C-extension wystawionych przez ten pakiet:

>>> 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 dla tej funkcji jest zdefiniowana this file.

Ważne jest, aby zdać sobie sprawę, że to nie jest możliwe dla pytona < 3,4 i trzeba przestrzegać pewnych zasad:

  • Trzeba to --\n\n po linii definicji podpisu.

  • Podpis musi znajdować się w pierwszym wierszu docletu.

  • Podpis musi być ważny, tzn. foo(a, b=1, c) nie działa, ponieważ nie można zdefiniować argumentów pozycyjnych po argumentach z wartością domyślną.

  • Możesz podać tylko jeden podpis. Więc to nie działa, jeśli używasz coś takiego:

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

to działa z 'inspect.signature'? – Eric

+0

@Eric Tak, o ile jest zgodny z regułami '__text_signature__', o których wcześniej wspomniałem. – MSeifert

+0

Brzmi jak rzecz, która 'numpy' potrzebuje łatki dla – Eric

Powiązane problemy