简体   繁体   English

设置嵌入式Python以编写C ++游戏脚本

[英]Setting up embedded Python for Scripting a C++ Game

I'm having trouble achieving this. 我在实现这个目标上遇到了麻烦。 What I'm stuck with is trying to expose Modules written in C++ to an embedded python interpreter. 我所坚持的是尝试将用C ++编写的模块暴露给嵌入式python解释器。

I'm using boost::python, but I'm not sure what I'm supposed to do for this, as the documentation seems to be lacking, to say the least. 我正在使用boost :: python,但是我不确定应该为此做些什么,因为至少似乎可以说缺少文档。

What I want is to expose some C++ code with BOOST_PYTHON_MODULE, and then access that from the same application . 我想要的是使用BOOST_PYTHON_MODULE公开一些C ++代码,然后从同一应用程序访问它。 However I can't get it to import. 但是我无法将其导入。 What I've got, which seem the closest (just relevant part): 我所拥有的,似乎是最接近的(只是相关的部分):

#include <python/interpreter.hpp>

bp::object blag() {
    return bp::str("Thingy");
}

BOOST_PYTHON_MODULE(modthingy) {
    bp::def("blag", &blag);
}


Interpreter::Interpreter() {
    Py_UnbufferedStdioFlag = 1;
    Py_Initialize();
    try {
        init_module_modthingy();
    } catch (bp::error_already_set) {
        PyErr_Print();
    }

    main_module = bp::import("__main__");
    main_namespace = main_module.attr("__dict__");
}

But that prints the Error AttributeError: 'NoneType' object has no attribute '__dict__' And I can't import the module later. 但这会打印出Error AttributeError: 'NoneType' object has no attribute '__dict__'并且我以后无法导入模块。

How should this be structured? 应该如何组织?

EDIT: Ok, so the closest I got was one of the methods in the accepted answer: 编辑:好的,所以我得到的最接近的方法是公认的答案中的一种方法:

PyImport_AppendInittab("modthingy", &PyInit_modthingy);
Py_Initialize();

However, this doesn't seem particularly useful in my case, as I'd like to be able to add/import modules after the Initialize function. 但是,这对于我来说似乎并不是特别有用,因为我希望能够在Initialize函数之后添加/导入模块。 I'm going to look into a few things, namely: 我将研究几件事,即:

  • See if I can get the suggested approach for python 2 working in python 3 看看我是否可以在python 3中获得python 2的建议方法
  • See if I can nicely structure my game to require naming all of the modules before Py_Initialize 看看我是否可以很好地构建游戏以要求在Py_Initialize之前命名所有模块

I'll update this post with my findings. 我将用我的发现更新这篇文章。

Boost.Python uses the BOOST_PYTHON_MODULE macro to define a Python module initializer. Boost.Python使用BOOST_PYTHON_MODULE宏来定义Python模块初始化程序。 The resulting function is not the module importer. 结果函数不是模块导入器。 This difference is similar to that of creating a modthingy.py module and calling import modthingy . 这种区别类似于创建modthingy.py模块并调用import modthingy

When importing a module, Python will first check if the module is a built-in module. 导入模块时,Python将首先检查该模块是否为内置模块。 If the module is not there, then Python will then search the module search path trying to find a python file or library based on the module name. 如果模块不存在,则Python将搜索模块搜索路径,以尝试根据模块名称查找python文件或库。 If a library is found, then Python expects the library to provide a function that will initialize the module. 如果找到了库,则Python希望该库提供一个将初始化模块的函数。 Once found, the import will create an empty module in the modules table, then initialize it. 找到后,导入将在modules表中创建一个空模块,然后对其进行初始化。 For statically linked modules, such as modthingy , the module search path will not be helpful, as there is no library for it to find. 对于静态链接的模块(例如modthingy ,模块搜索路径将无济于事,因为没有库可供查找。

For embedding, the module table and initialization function documentation states that for static modules, the module initializer function will not be automatically called unless there is an entry in the initialization table. 对于嵌入, 模块表和初始化函数文档指出对于静态模块,除非初始化表中有条目,否则不会自动调用模块初始化器函数。 For Python 2 and Python 3, one can accomplish this by calling PyImport_AppendInittab() before Py_Initialize() : 对于Python 2和Python 3,可以通过在PyImport_AppendInittab()之前调用PyImport_AppendInittab()来实现此Py_Initialize()

BOOST_PYTHON_MODULE(modthingy)
{
  // ...
}

PyImport_AppendInittab("modthingy", &initmodthingy);
Py_Initialize();
// ...
boost::python::object modthingy = boost::python::import("modthingy");

Alternatively, for Python 2, once the interpreter has been initialized, one can create an empty module that is added to the modules dictionary via PyImport_AddModule() , then explicitly initialize the module. 另外,对于Python 2,解释器初始化后,可以创建一个空模块,该模块通过PyImport_AddModule()添加到模块字典中,然后显式初始化该模块。

BOOST_PYTHON_MODULE(modthingy)
{
  // ...
}

Py_Initialize();
PyImport_AddModule("modythingy");
initmodthingy();
boost::python::object modthingy = boost::python::import("modthingy");

This approach is demonstrated in the official Python embedded demo, embed/demo.c . 在官方的Python嵌入式演示embed / demo.c中演示了这种方法。 The module initializer created from BOOST_PYTHON_MODULE does not call PyImport_AddModule() , thus it must be explicitly called. BOOST_PYTHON_MODULE创建的模块初始化器不会调用PyImport_AddModule() ,因此必须显式调用它。

Also note that the Python's C API for embedding changed naming conventions for module initialization functions between Python 2 and 3, so for BOOST_PYTHON_MODULE(modthingy) , one may need to use &initmodthingy for Python 2 and &PyInit_modthingy for Python 3. 还注意到,Python的用于嵌入用于Python 2和3之间模块初始化函数改变的命名约定,因此对于C API BOOST_PYTHON_MODULE(modthingy)一个可能需要使用&initmodthingy为Python 2和&PyInit_modthingy为Python 3。


Here is a minimal complete example demonstrating importing a module statically linked with the embedded interpreter: 这是一个最小的完整示例,演示如何导入与嵌入式解释器静态链接的模块:

#include <iostream>
#include <string>

#include <boost/python.hpp>

std::string spam() { return "Spam spam spam"; }

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::def("spam", &spam);
}

int main()
{
  // Add example to built-in.
  PyImport_AppendInittab("example", &initexample);

  // Start the interpreter.
  Py_Initialize();

  namespace python = boost::python;
  try
  {
    // >>> import example
    python::object example = python::import("example");
    // >>> x = example.spam()
    python::object x = example.attr("spam")();
    // >>> print x
    std::cout << "x = " << python::extract<std::string>(x)() << std::endl;
  }
  catch (const python::error_already_set&)
  {
    PyErr_Print();
  }
}

Output: 输出:

x = Spam spam spam

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM