在模块中组合C和Python函数

时间:2009-06-18 15:41:00

标签: python cpython

我有一个C扩展模块,我想添加一些Python实用程序功能。有推荐的方法吗?

例如:

import my_module

my_module.super_fast_written_in_C()
my_module.written_in_Python__easy_to_maintain()

我主要对Python 2.x感兴趣。

3 个答案:

答案 0 :(得分:7)

通常的做法是:mymod.py包含用Python编写的实用程序函数,并导入_mymod模块中的好东西,该模块用C编写并从_mymod.so或_mymod.pyd导入。例如,查看Python发行版中的... / Lib / csv.py。

答案 1 :(得分:5)

使用下划线为您的原生扩展名添加前缀。 然后,在Python中,创建一个包装器模块,该模块导入该本机扩展,并在其上添加一些其他非本机例程。

答案 2 :(得分:1)

现有答案描述了最常用的方法:它具有在已编译的C扩展不可用的平台上允许纯Python(或其他语言)实现的潜在优势(包括Jython和IronPython)。

然而,在少数情况下,将模块拆分为C层和Python层可能不值得提供一些在Python中比在C中更合理地编写的附加内容。例如,{{3} }(此时为7113行),为了启用gmpy类型实例的pickle,使用:

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

如果你希望那些额外的功能在你的模块中“坚持”(在这个例子中不是必需的话),你当然会使用由Py_InitModule3构建的模块对象(或其他任何方法)和其PyModule_GetDict而非临时字典作为PyRun_String的名称空间。当然,除了PyRun_String所需的defclass语句之外,还有更复杂的方法,但是,对于足够简单的情况,这种简单的方法实际上可能就足够了。