可以将内置表中的静态Python模块用作Python包的子模块吗?

时间:2019-06-21 13:31:37

标签: python python-3.x python-2.7 static-linking cpython

在具有Python支持的静态VTK构建中,Python模块是静态编译的。这些模块然后链接到vtkpython二进制文件中,并在初始化Python解释器之前添加到内置表中。我们不能使用共享的Python模块,因为这样最终会将静态全局变量从核心库复制到每个共享的Python模块中。

我尝试通过手动添加到sys.modules来“诱骗”进口机器:

Python 2.7.16 (default, Apr 30 2019, 15:54:59) 
[GCC 8.3.1 20190223 (Red Hat 8.3.1-2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> import math
>>> sys.modules['vtkmodules.vtkCommonCorePython'] = math
>>> import vtkmodules.vtkCommonCorePython
>>> import vtkmodules
>>> from vtkmodules import vtkCommonCorePython
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name vtkCommonCorePython

,因此无法在Python2中以这种方式欺骗导入机制。对于Python3,可能会有这样的希望能够奏效:

% bin/vtkpython
Python 3.7.3 (default, May 11 2019, 00:45:16) 
[GCC 8.3.1 20190223 (Red Hat 8.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> import math
>>> sys.modules['vtkmodules.vtkCommonCorePython'] = math
>>> from vtkmodules import vtkCommonCorePython
>>> vtkCommonCorePython.sin
<built-in function sin>

这是相关的代码(正在使用的完整代码是here,但是为了简化起见,我删除了在我的构建中被禁用的MPI位和一些VTK日志到终端代码)。

#include "vtkPython.h"
#include "vtkPythonCompatibility.h"

#include "vtkPythonInterpreter.h"
#include "vtkpythonmodules.h"
#include <vtksys/SystemTools.hxx>
// SNIP: some headers removed for brevity.

#include <string>

int main(int argc, char **argv)
{
  std::string fullpath;
  std::string error;

  if (vtksys::SystemTools::FindProgramPath(argv[0], fullpath, error))
  {
    vtkPythonInterpreter::SetProgramName(fullpath.c_str());
  }

  // SNIP: MPI setup (associated class also removed above)

  /**
   * This function is generated and exposed in vtkpythonmodules.h.
   * This registers any Python modules for VTK for static builds.
   */
  vtkpythonmodules_load();

  // SNIP: VTK log-to-terminal logic

  return vtkPythonInterpreter::PyMain(argc, argv);
}

vtkpythonmodules_load()函数是由绑定包装器逻辑生成的,它看起来像是用于静态构建的(为简洁起见,它已被剪掉):

#include "vtkCommonCorePython.h"
// SNIP: Includes for other Python init functions.
#if PY_VERSION_HEX < 0x03000000         
#define PY_IMPORT(module) PyImport_AppendInittab("vtkmodules." #module, init ## module)            
#else                                     
#define PY_IMPORT(module) PyImport_AppendInittab("vtkmodules." #module, PyInit_ ## module)         
#endif                                

static void vtkpythonmodules_load() {     
  PY_IMPORT(vtkCommonCorePython);
  // SNIP: PY_IMPORT calls for the rest of VTK's modules.
}

vtkmodules软件包是Python代码(包括供用户实际导入的包装程序,以确保也导入了相关模块)。例如,vtkmodules/vtkCommonDataModel.py如下所示:

from __future__ import absolute_import
from . import vtkCommonCore
from . import vtkCommonMath
from . import vtkCommonTransforms
from .vtkCommonDataModelPython import *

以确保首先加载vtkCommonDataModelPython中使用的C ++类。

我希望在这种情况下可以使用内置模块,但似乎不行。有没有办法做到这一点?如果不是,那是以前没有必要并且没有人问过的东西,还是明确地不支持它?谢谢。

1 个答案:

答案 0 :(得分:0)

似乎一种潜在的解决方案是将所有内置模块放在顶层,而不是放在软件包内部。现在这对我们来说是合适的,因为无论如何我们的编译模块名称都是实现细节,并且我们有蹦床.py文件来正确确定依赖顺序,以便在派生类型之前正确注册基本类型。我们的修复程序在this MR中进行了描述。