Domanda

Ho un modulo di estensione C, al quale vorrei aggiungere alcune funzioni di utilità Python. Esiste un modo consigliato per farlo?

Ad esempio:

import my_module

my_module.super_fast_written_in_C()
my_module.written_in_Python__easy_to_maintain()

Sono principalmente interessato a Python 2.x.

È stato utile?

Soluzione

Il solito modo per farlo è: mymod.py contiene le funzioni di utilità scritte in Python e importa le chicche nel modulo _mymod che è scritto in C e viene importato da _mymod.so o _mymod.pyd. Ad esempio, guarda ... / Lib / csv.py nella tua distribuzione Python.

Altri suggerimenti

Prefisso l'estensione nativa con un trattino basso. Quindi, in Python, crea un modulo wrapper che importa quell'estensione nativa e aggiunge anche altre routine non native.

Le risposte esistenti descrivono il metodo più spesso usato: ha il potenziale vantaggio di consentire implementazioni pure-Python (o altro linguaggio) su piattaforme in cui l'estensione C compilata non è disponibile (inclusi Jython e IronPython).

In alcuni casi, tuttavia, potrebbe non essere utile suddividere il modulo in un livello C e un livello Python solo per fornire alcuni extra scritti in modo più sensato in Python rispetto a C. Ad esempio, gmpy (righe 7113 e seguenti), in ordine per abilitare il decapaggio delle istanze del tipo gmpy , usa:

copy_reg_module = PyImport_ImportModule("copy_reg");
if (copy_reg_module) {
    char* enable_pickle =
        "def mpz_reducer(an_mpz): return (gmpy.mpz, (an_mpz.binary(), 256))\n"
        "def mpq_reducer(an_mpq): return (gmpy.mpq, (an_mpq.binary(), 256))\n"
        "def mpf_reducer(an_mpf): return (gmpy.mpf, (an_mpf.binary(), 0, 256))\n"
        "copy_reg.pickle(type(gmpy.mpz(0)), mpz_reducer)\n"
        "copy_reg.pickle(type(gmpy.mpq(0)), mpq_reducer)\n"
        "copy_reg.pickle(type(gmpy.mpf(0)), mpf_reducer)\n"
    ;
    PyObject* namespace = PyDict_New();
    PyObject* result = NULL;
    if (options.debug)
        fprintf(stderr, "gmpy_module imported copy_reg OK\n");
    PyDict_SetItemString(namespace, "copy_reg", copy_reg_module);
    PyDict_SetItemString(namespace, "gmpy", gmpy_module);
    PyDict_SetItemString(namespace, "type", (PyObject*)&PyType_Type);
    result = PyRun_String(enable_pickle, Py_file_input,
                          namespace, namespace);

Se desideri che quelle poche funzioni extra rimangano " nel tuo modulo (non necessario in questo caso di esempio), ovviamente utilizzeresti l'oggetto module come costruito da Py_InitModule3 (o qualunque altro metodo) e il suo PyModule_GetDict anziché un dizionario temporaneo come spazio dei nomi in cui PyRun_String . E naturalmente ci sono approcci più sofisticati rispetto a PyRun_String le istruzioni def e class di cui hai bisogno, ma, per casi abbastanza semplici, questo semplice approccio potrebbe in effetti essere sufficiente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top