gpt4 book ai didi

python - 如何扩展 Python 并制作 C 包?

转载 作者:行者123 更新时间:2023-12-04 10:03:47 26 4
gpt4 key购买 nike

不久前,我在我的 C 应用程序中嵌入并扩展了 Python 2.7。在火车的后期,我将它带到了 Python 3,并且模块注册的许多初始化都为我改变了。

在我使用 PyModule_Create 之前创建模块并在之后添加成员,甚至是子模块,以便我可以执行:

from foo.bar import bas

我将“顶级”模块添加/附加到 PyEval_GetBuiltins() ,这在 Py 2 中可能是错误的,但它确实有效。现在在 Py 3 中,我在上面的代码中收到了这个异常:
Traceback (most recent call last):
File "foo.py", line 1, in <module>
ModuleNotFoundError: No module named 'foo.bar'; 'foo' is not a package

查找文档,我现在发现了一个带有 PyImport_ExtendInittab 的示例.我对此有两个问题:

1) 什么是 Inittab应该是什么意思?文档说明了它的含义,但这个命名有点令人讨厌。什么是 Inittab ?不应该叫 PyImport_ExtendBuiltins ,我会理解的。

2)我只能找到添加普通模块的示例。正在使用 PyImport_ExtendInittab 创建带有子模块的包也?

非常感谢!

最佳答案

我不知道你想在这里拉什么(嵌套扩展模块)是否可以,无论如何推荐的结构化代码方式是通过[Python 3.Docs]: Modules - Packages .但是,我这样做(重现问题,修复它)作为个人练习。

1. 介绍

列出 2 个相关页面:

  • [Python 3.Docs]: Module Objects
  • [Python 2.Docs]: Module Objects

  • 环境:

    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q061692747]> tree /a /f
    Folder PATH listing for volume SSD0-WORK
    Volume serial number is AE9E-72AC
    E:.
    | test00.py
    |
    +---py2
    | mod.c
    |
    \---py3
    helper.c
    mod.c


    2.Python 2

    试图重现问题中提到的行为的虚拟模块。

    模组.c:

    #include <stdio.h>
    #include <Python.h>

    #define MOD_NAME "mod"
    #define SUBMOD_NAME "submod"


    static PyObject *pMod = NULL;
    static PyObject *pSubMod = NULL;

    static PyMethodDef modMethods[] = {
    {NULL}
    };


    PyMODINIT_FUNC initmod() {
    if (!pMod) {
    pMod = Py_InitModule(MOD_NAME, modMethods);
    if (pMod) {
    PyModule_AddIntConstant(pMod, "i", -69);
    pSubMod = Py_InitModule(MOD_NAME "." SUBMOD_NAME, modMethods);
    if (pSubMod) {
    PyModule_AddStringConstant(pSubMod, "s", "dummy");
    if (PyModule_AddObject(pMod, SUBMOD_NAME, pSubMod) < 0) {
    Py_XDECREF(pMod);
    Py_XDECREF(pSubMod);
    return;
    }
    }
    }
    }
    }

    输出 :

    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q061692747\py2]> sopr.bat
    *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***

    [prompt]> "f:\Install\pc032\Microsoft\VisualCForPython2\2008\Microsoft\Visual C++ for Python\9.0\vcvarsall.bat" x64
    Setting environment for using Microsoft Visual Studio 2008 x64 tools.

    [prompt]> dir /b
    mod.c

    [prompt]> cl /nologo /MD /DDLL /I"c:\Install\pc064\Python\Python\02.07.17\include" mod.c /link /NOLOGO /DLL /OUT:mod.pyd /LIBPATH:"c:\Install\pc064\Python\Python\02.07.17\libs"
    mod.c
    Creating library mod.lib and object mod.exp

    [prompt]> dir /b
    mod.c
    mod.exp
    mod.lib
    mod.obj
    mod.pyd
    mod.pyd.manifest

    [prompt]> "e:\Work\Dev\VEnvs\py_pc064_02.07.17_test0\Scripts\python.exe"
    Python 2.7.17 (v2.7.17:c2f86d86e6, Oct 19 2019, 21:01:17) [MSC v.1500 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys
    >>>
    >>> [item for item in sys.modules if "mod" in item]
    []
    >>> import mod
    >>>
    >>> [item for item in sys.modules if "mod" in item] # !!! NOTICE the contents !!!
    ['mod.submod', 'mod']
    >>>
    >>> mod
    <module 'mod' from 'mod.pyd'>
    >>> mod.i
    -69
    >>> mod.submod
    <module 'mod.submod' (built-in)>
    >>> mod.submod.s
    'dummy'
    >>>
    >>> from mod.submod import s
    >>> s
    'dummy'
    >>>


    如所见,导入带有子模块的模块,在 sys.path 中添加子模块(没有看,但我 99.99% 确定这是由 Py_InitModule 执行的)

    3.Python 3

    转换为 Python 3。由于这是第一步,因此将 2 条注释行视为不存在。

    模组.c:

    #include <stdio.h>
    #include <Python.h>
    //#include "helper.c"

    #define MOD_NAME "mod"
    #define SUBMOD_NAME "submod"


    static PyObject *pMod = NULL;
    static PyObject *pSubMod = NULL;

    static PyMethodDef modMethods[] = {
    {NULL}
    };

    static struct PyModuleDef modDef = {
    PyModuleDef_HEAD_INIT, MOD_NAME, NULL, -1, modMethods,
    };

    static struct PyModuleDef subModDef = {
    PyModuleDef_HEAD_INIT, MOD_NAME "." SUBMOD_NAME, NULL, -1, modMethods,
    };


    PyMODINIT_FUNC PyInit_mod() {
    if (!pMod) {
    pMod = PyModule_Create(&modDef);
    if (pMod) {
    PyModule_AddIntConstant(pMod, "i", -69);
    pSubMod = PyModule_Create(&subModDef);
    if (pSubMod) {
    PyModule_AddStringConstant(pSubMod, "s", "dummy");
    if (PyModule_AddObject(pMod, SUBMOD_NAME, pSubMod) < 0) {
    Py_XDECREF(pMod);
    Py_XDECREF(pSubMod);
    return NULL;
    }
    //addToSysModules(MOD_NAME "." SUBMOD_NAME, pSubMod);
    }
    }
    }
    return pMod;
    }

    输出 :

    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q061692747\py3]> sopr.bat
    *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***

    [prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2017\VC\Auxiliary\Build\vcvarsall.bat" x64
    **********************************************************************
    ** Visual Studio 2017 Developer Command Prompt v15.9.23
    ** Copyright (c) 2017 Microsoft Corporation
    **********************************************************************
    [vcvarsall.bat] Environment initialized for: 'x64'

    [prompt]> dir /b
    helper.c
    mod.c

    [prompt]> cl /nologo /MD /DDLL /I"c:\Install\pc064\Python\Python\03.07.06\include" mod.c /link /NOLOGO /DLL /OUT:mod.pyd /LIBPATH:"c:\Install\pc064\Python\Python\03.07.06\libs"
    mod.c
    Creating library mod.lib and object mod.exp

    [prompt]> dir /b
    helper.c
    mod.c
    mod.exp
    mod.lib
    mod.obj
    mod.pyd

    [prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe"
    Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys
    >>>
    >>> [item for item in sys.modules if "mod" in item]
    []
    >>> import mod
    >>>
    >>> [item for item in sys.modules if "mod" in item] # !!! NOTICE the contents !!!
    ['mod']
    >>>
    >>> mod
    <module 'mod' from 'e:\\Work\\Dev\\StackOverflow\\q061692747\\py3\\mod.pyd'>
    >>> mod.i
    -69
    >>> mod.submod
    <module 'mod.submod'>
    >>> mod.submod.s
    'dummy'
    >>>
    >>> from mod.submod import s
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    ModuleNotFoundError: No module named 'mod.submod'; 'mod' is not a package
    >>> ^Z


    [prompt]>


    正如所见,嵌套导入是不可能的。那是因为 sys.modules 中不存在 mod.submod。作为概括,“嵌套”扩展子模块不再可以通过包含它们的初始化函数的模块导入。唯一的选择是手动导入它们。作为说明:我认为 这个 Python 3 的限制是有原因的,所以下面的内容就像玩火 .

    从 mod.c 中删除 2 行.

    助手.c:

    int addToSysModules(const char *pName, PyObject *pMod) {
    PyObject *pSysModules = PySys_GetObject("modules");
    if (!PyDict_Check(pSysModules)) {
    return -1;
    }
    PyObject *pKey = PyUnicode_FromString(pName);
    if (!pKey) {
    return -2;
    }
    if (PyDict_Contains(pSysModules, pKey)) {
    Py_XDECREF(pKey);
    return -3;
    }
    Py_XDECREF(pKey);
    if (PyDict_SetItemString(pSysModules, pName, pMod) == -1)
    {
    return -4;
    }
    return 0;
    }

    输出 :

    [prompt]> cl /nologo /MD /DDLL /I"c:\Install\pc064\Python\Python\03.07.06\include" mod.c  /link /NOLOGO /DLL /OUT:mod.pyd /LIBPATH:"c:\Install\pc064\Python\Python\03.07.06\libs"
    mod.c
    Creating library mod.lib and object mod.exp

    [prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe"
    Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>>
    >>> import sys
    >>>
    >>> [item for item in sys.modules if "mod" in item]
    []
    >>> import mod
    >>>
    >>> [item for item in sys.modules if "mod" in item] # !!! NOTICE the contents :) !!!
    ['mod.submod', 'mod']
    >>>
    >>> from mod.submod import s
    >>> s
    'dummy'
    >>>


    4. 结束语

    正如我上面所说,这似乎更像是一种解决方法。更简洁的解决方案是通过包更好地组织模块。

    由于这是出于演示目的,并且为了使代码尽可能简单,我并不总是检查 Python C API 函数返回代码。这可能导致难以发现错误(甚至崩溃)和 永远不应该这样做 (尤其是在生产代码中)。

    我不太确定 PyImport_ExtendInittab 效果到底是什么,因为我没有玩过它,但是 [Python 3.Docs]: Importing Modules - int PyImport_ExtendInittab(struct _inittab *newtab)状态( 强调 是我的):

    This should be called before Py_Initialize().



    因此,在我们的上下文中调用它是不可能的。

    还提到这个(旧)讨论(不确定它是否包含相关信息,但仍然) [Python.Mail]: [Python-Dev] nested extension modules? .

    关于python - 如何扩展 Python 并制作 C 包?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61692747/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com