无法使用 Python 3 加载 Python 模块

问题描述

#include <Python.h>
#include <fstream>
#include <iostream>
#include <string>
#include <filesystem>
#include <sys/types.h>

#include <dirent.h>


static const char * sPythonCode =
"class Test :\n"
"   def __init__(self) : \n"
"     self.disc_ = 0. \n"
"   def getset(self) : \n"
"     self.disc_ = 7. \n"
"     return self.disc_ \n";


std::string writeFile()
{
   static int iFile = 0;
   std::string sFileName(std::string("test") + std::to_string(iFile));
   std::ofstream out("py/" + sFileName + ".py");
   out << sPythonCode;
   out.flush();
   out.close();
   iFile++;
   return sFileName;
}

static bool bPythonopen = false;
#define PYTHONPATHLEN 501

static void _PyInit()
{
   if (!Py_IsInitialized())
   {
      Py_InitializeEx(0);
   }
}

void openPython(void)
{
   if (!bPythonopen)
   {
      const size_t szBufferN = 1000;
      char acLoadpath[szBufferN];
      const char *pypath = "./py";

      _PyInit();

      PyRun_SimpleString("import sys");
      PyRun_SimpleString("print('python (%d.%d.%d) initialized' % (sys.version_info.major,sys.version_info.minor,sys.version_info.micro))");
      PyRun_SimpleString("print('--------------------------')");


      snprintf(acLoadpath,szBufferN,"sys.path.append('%s')",pypath);
      PyRun_SimpleString(acLoadpath);

      bPythonopen = true;
   }
}

PyObject *loadpythonmodule(const char *acModule)
{
   PyObject *pyModule = NULL;

   if (bPythonopen && acModule && strcmp(acModule,""))
   {
      printf("%s\n",acModule);
      pyModule = PyImport_ImportModule(acModule);
      if (!pyModule)
      {
         PyErr_Print();
      }
   }
   return pyModule;
}

void loadPython()
{

   std::string sFileName = writeFile();

   openPython();
   //sleep(1);
   PyObject *ppythonmodule = loadpythonmodule(sFileName.c_str());
   
   if (ppythonmodule)
      PyDict_DelItemString(PyImport_GetModuleDict(),PyModule_GetName((PyObject *)ppythonmodule));
}

int main(int argc,char **argv)
{
   for (int i = 0; i < 10; i++)
   {     
      loadPython();
   }
}

我的工作环境:

  • gcc 版本 8.3.1 20190311 (Red Hat 8.3.1-3) (GCC)
  • 红帽企业 Linux 服务器 7.6 版 (Maipo)
  • python 3.6.10 / 3.8.3 的问题

编译命令:

g++ pythontest.cpp -I/Opt/python/python3.6.10/include/python3.6m -L/opt/python/python3.6.10/lib -lpython3.6m

创建py目录:

mkdir py

当我运行此代码时,我在加载的不同测试文件上出现随机错误

输出示例:

python (3.6.10) initialized
--------------------------
test0
test1
test2
test3
ModuleNotFoundError: No module named 'test3'
test4
test5
ModuleNotFoundError: No module named 'test5'
test6
test7
ModuleNotFoundError: No module named 'test7'
test8
test9
ModuleNotFoundError: No module named 'test9'

很高兴知道:

  • 如果我取消对 sleep 行的注释,效果会很好
  • 如果我删除 iFile++,它也会像在已经创建的文件之后使用一样工作
  • 如果我在没有 rm -rf py 目录的情况下重新启动一秒钟,它也可以运行
  • 如果我在 loadPython 函数中每次运行后删除文件删除 iFile++ 它也可以工作
  • 如果我使用 strace 启动可执行文件,我看不到问题

目前似乎 Python 加载程序没有看到磁盘上的文件,但是如果我打印目录中的内容,由于 dirent,我会看到 testx.py

请注意,我们在不同的 Linux 服务器上重现了该错误(不是硬件问题,甚至在 Windows 上),使用 Python 2.7.x 时它运行良好。

解决方法

每次修改模块文件夹时都应该调用 __import__('importlib').invalidate_caches() 以让 C Python 知道它必须再次读取目录。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...