如何扩展Python并制作C包?

如何扩展Python并制作C包?,python,cpython,python-extensions,python-embedding,Python,Cpython,Python Extensions,Python Embedding,不久前,我在我的C应用程序中嵌入并扩展了Python2.7。在火车晚点的时候,我把它带到了Python3上,很多模块注册的初始化对我来说都改变了 之前,我使用PyModule\u Create创建模块,然后添加成员,甚至子模块,以便执行: from foo.bar import bas 我在PyEval\u GetBuiltins()中添加/附加了“顶级”模块,这在py2中可能是错误的,但它起了作用。现在在Py 3中,我收到上述代码的异常: Traceback (most recent cal

不久前,我在我的C应用程序中嵌入并扩展了Python2.7。在火车晚点的时候,我把它带到了Python3上,很多模块注册的初始化对我来说都改变了

之前,我使用
PyModule\u Create
创建模块,然后添加成员,甚至子模块,以便执行:

from foo.bar import bas
我在PyEval\u GetBuiltins()中添加/附加了“顶级”模块,这在py2中可能是错误的,但它起了作用。现在在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
回溯(最近一次呼叫最后一次):
文件“foo.py”,第1行,在
ModuleNotFoundError:没有名为“foo.bar”的模块;'“foo”不是一个包
查找文档,我现在发现了一个带有
PyImport\u ExtendInittab
的示例。关于这一点,我有两个问题:

1)
Inittab
应该是什么意思?医生说了它的意思,但这个名字有点令人恼火。什么是
Inittab
?我能理解,它不应该被称为
PyImport\u extendedbuiltins

2) 我只能找到添加普通模块的示例。使用
PyImport\u ExtendInittab
也可以创建包含子模块的包吗


非常感谢

如果没有一个最小的可重复的例子,就很难判断出问题所在,也很难在答案中明确寻找什么。不过,我会尽力提供一些协助

from foo.bar import bas
要使上述功能正常工作,您需要一个名为foo的文件夹中的bar.py文件,并且bar.py必须包含一个函数
bas()
。此外,文件夹foo必须包含一个空的uuu init_uuuu.py文件

现在,如果您想在某个地方调用已编译的C文件,那么最简单的方法可能是使用
os.system()
subprocess.call()
并调用该文件,就像从命令行调用它一样

假设make文件位于同一目录中:

import os
import subprocess

os.system("make run")

# or
subprocess.run("make run".split())
其中,
makerun
根据需要运行C文件(在makefile中声明)。还可以使用pythonf-strings随意传递关键字参数


希望这能有所帮助。

我不知道您在这里尝试拉什么(嵌套的扩展模块)是否合适,无论如何,构建代码的推荐方法是通过
然而,我这样做(重现问题,解决问题)是作为个人练习

1.简介 列出2个相关页面:

环境:


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

c部分:

#包括
#包括
#定义MOD_名称“MOD”
#定义SUBMOD_名称“SUBMOD”
静态PyObject*pMod=NULL;
静态PyObject*pSubMod=NULL;
静态PyMethodDef modMethods[]={
{NULL}
};
PyMODINIT_FUNC initmod(){
如果(!pMod){
pMod=Py_InitModule(MOD_名称,modMethods);
如果(pMod){
PyModule_附加常数(pMod,“i”,-69);
pSubMod=Py_InitModule(MOD_NAME.“SUBMOD_NAME,modMethods”);
如果(pSubMod){
PyModule_AddStringConstant(pSubMod,“s”,“虚拟”);
if(PyModule\u AddObject(pMod,SUBMOD\u NAME,pSubMod)<0){
Py_XDECREF(pMod);
Py_XDECREF(pSubMod);
返回;
}
}
}
}
}
输出

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q061692747\py2]>sopr.bat
***设置较短的提示,以便粘贴到StackOverflow(或其他)页面时更适合***
[ FP] > F\ \安装\PC032 \微软\VisualCfPythON2 \ 2008 \微软\Visual C++,用于Python \\\vcValsAL.BAT“X64”
设置使用Microsoft Visual Studio 2008 x64工具的环境。
[提示]>dir/b
c型
[提示]>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”
c型
创建库mod.lib和对象mod.exp
[提示]>dir/b
c型
mod.exp
mod.lib
mod.obj
mod.pyd
mod.pyd.manifest
[提示]>“e:\Work\Dev\VEnvs\py\u pc064\u 02.07.17\u test0\Scripts\python.exe”
win32上的Python 2.7.17(v2.7.17:c2f86d86e6,2019年10月19日,21:01:17)[MSC v.1500 64位(AMD64)]
有关详细信息,请键入“帮助”、“版权”、“信用证”或“许可证”。
>>>导入系统
>>>
>>>[如果项目中的“mod”,则系统模块中的项目对应项目]
[]
>>>导入模式
>>>
>>>[系统模块中的项目,如果项目中的“mod”]#!!!注意内容!!!
['mod.submod','mod']
>>>
>>>国防部
>>>i型
-69
>>>mod.submod
>>>mod.submod.s
“哑巴”
>>>
>>>从mod.submod导入
>>>
“哑巴”
>>>
如图所示,导入带有子模块的模块时,会在sys.path中添加子模块(没有查看,但我99.99%确定这是由Py_InitModule执行的)


3.Python 3 转换为Python 3。因为这是第一步,所以将2条注释行视为不存在

c部分:

#包括
#包括
//#包括“helper.c”
#定义MOD_名称“MOD”
#定义SUBMOD_名称“SUBMOD”
静态PyObject*pMod=NULL;
静态PyObject*pSubMod=NULL;
静态PyMethodDef modMethods[]={
{NULL}
};
静态结构PyModuleDef modDef={
PyModuleDef\u HEAD\u INIT,MOD\u NAME,NULL,-1,modMethods,
};
静态结构PyModuleDef subModDef={
PyModuleDef\u HEAD\u INIT,MOD\u NAME“.”子MOD\u NAME,NULL,-1,modMethods,
};
PyMODINIT_FUNC PyInit_mod(){
如果(!pMod){
pMod=PyModule_Create(&modDef);
如果(pMod){
PyModule_附加常数(pMod,“i”,-69);
pSubMod=PyModule_Create(&subModDef);
如果(pSubMod){
PyModule_AddStringConstant(pSubMod,“s”,“虚拟”);
if(PyModule\u AddObject(pMod,SUBMOD\u NAME,pSubMod)<0){
Py_XDECREF(pMod);
Py_XDECREF(pSubMod);
返回NULL;
}
//addToSysModules(MOD_NAME.“SUBMOD_NAME,pSubMod”);
}
}
}
返回pMod
[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
    @classmethod
    def find_spec(cls, fullname, path=None, target=None):
        if path is not None:
            return None
        if _imp.is_builtin(fullname):
            return spec_from_loader(fullname, cls, origin=cls._ORIGIN)
        else:
            return None
__path__ = None
import importlib.abc
import importlib.machinery
import importlib.util
import sys


class CustomBuiltinImporter(importlib.abc.MetaPathFinder):
    _ORIGIN = 'custom-builtin'

    @classmethod
    def find_spec(cls, fullname, path, target=None):
        if path != __path__ or not fullname.startswith(cls.__module__ + '.'):
            return None
        if fullname not in sys.builtin_module_names:
            return None
        return importlib.util.spec_from_loader(fullname, importlib.machinery.BuiltinImporter, origin=cls._ORIGIN)


sys.meta_path.append(CustomBuiltinImporter)