Pergunta

Eu tenho um módulo de extensão C, à qual gostaria de adicionar algumas funções utilitárias Python. Existe uma maneira recomendada de fazer isso?

Por exemplo:

import my_module

my_module.super_fast_written_in_C()
my_module.written_in_Python__easy_to_maintain()

Estou interessado principalmente em Python 2.x.

Foi útil?

Solução

A maneira usual de fazer isso é: mymod.py contém as funções de utilidade escritos em Python e as importações os presentes no módulo _mymod que é escrito em C e é importados da _mymod.so ou _mymod.pyd. Por exemplo, olhar para ... / lib / csv.py na sua distribuição Python.

Outras dicas

Prefixo sua extensão nativa com um sublinhado. Então, em Python, criar um módulo de wrapper que as importações que extensão nativa e acrescenta algumas outras rotinas de não-nativos em cima disso.

As respostas existentes descrever o método mais utilizado: tem a vantagem potencial de permitir puro-Python (ou outra linguagem) implementações em plataformas em que a extensão C compilado não está disponível (incluindo Jython e IronPython)

Em alguns casos, no entanto, pode não valer a pena divisão o módulo em uma camada de C e uma camada Python apenas para fornecer alguns extras que são mais sensivelmente escritos em Python que em C. Por exemplo, gmpy (linhas 7113 ff neste momento), em ordem para permitir decapagem de instâncias do tipo, usos de gmpy:

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 você quiser aquelas poucas funções extras para "ficar por aqui" no seu módulo (não é necessário neste caso exemplo), você teria de usar naturalmente o seu objeto módulo como construído por Py_InitModule3 (ou qualquer outro método) e sua PyModule_GetDict em vez de um transiente dicionário como o namespace em que a PyRun_String. E é claro que existem abordagens mais sofisticadas do que PyRun_String os def e class declarações que você precisa, mas, para os casos suficientes simples, esta abordagem simples pode de fato ser suficiente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top