在模块中组合 C 和 Python 函数

发布于 2024-07-24 11:06:07 字数 223 浏览 5 评论 0原文

我有一个 C 扩展模块,我想向其中添加一些 Python 实用函数。 有推荐的方法吗?

例如:

import my_module

my_module.super_fast_written_in_C()
my_module.written_in_Python__easy_to_maintain()

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

I have a C extension module, to which I would like to add some Python utility functions. Is there a recommended way of doing this?

For example:

import my_module

my_module.super_fast_written_in_C()
my_module.written_in_Python__easy_to_maintain()

I'm primarily interested in Python 2.x.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

山川志 2024-07-31 11:06:07

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

The usual way of doing this is: mymod.py contains the utility functions written in Python, and imports the goodies in the _mymod module which is written in C and is imported from _mymod.so or _mymod.pyd. For example, look at .../Lib/csv.py in your Python distribution.

拿命拼未来 2024-07-31 11:06:07

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

Prefix your native extension with an underscore.
Then, in Python, create a wrapper module that imports that native extension and adds some other non-native routines on top of that.

oО清风挽发oО 2024-07-31 11:06:07

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

然而,在某些情况下,仅仅为了提供一些用 Python 编写的比用 C 编写更明智的额外功能,可能不值得将模块拆分为 C 层和 Python 层。例如,gmpy(此时为第 7113 行),以便启用酸洗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);

如果您希望这些额外的函数“保留”在您的模块中(在本示例中没有必要),您当然可以将模块对象用作由 Py_InitModule3 (或任何其他方法)及其 PyModule_GetDict 构建,而不是使用瞬态字典作为 PyRun_String 的命名空间。 当然,还有比您需要的 PyRun_String def 和 class 语句更复杂的方法,但是,对于足够简单的情况,这种简单的方法事实上可能就足够了。

The existing answers describe the method most often used: it has the potential advantage of allowing pure-Python (or other-language) implementations on platforms in which the compiled C extension is not available (including Jython and IronPython).

In a few cases, however, it may not be worth splitting the module into a C layer and a Python layer just to provide a few extras that are more sensibly written in Python than in C. For example, gmpy (lines 7113 ff at this time), in order to enable pickling of instances of gmpy's type, uses:

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

If you want those few extra functions to "stick around" in your module (not necessary in this example case), you would of course use your module object as built by Py_InitModule3 (or whatever other method) and its PyModule_GetDict rather than a transient dictionary as the namespace in which to PyRun_String. And of course there are more sophisticated approaches than to PyRun_String the def and class statements you need, but, for simple enough cases, this simple approach may in fact be sufficient.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文