Here is canonical example of a program extending embedded Python 3.x in C/C++:
#include <Python.h>
//// Definition of 'emb' Python module ////////////////////
static PyObject* emb_foo(PyObject *self, PyObject *args)
{
char const* n = "I am foo";
return Py_BuildValue("s", n);
}
static PyMethodDef EmbMethods[] = {
{"foo", emb_foo, METH_VARARGS, "Returns foo"},
{NULL, NULL, 0, NULL}
};
static PyModuleDef EmbModule = {
PyModuleDef_HEAD_INIT, "emb", NULL, -1, EmbMethods,
NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb(void)
{
return PyModule_Create(&EmbModule);
}
//// Embedded Python with 'emb' loaded ////////////////////
int main()
{
PyImport_AppendInittab("emb", &PyInit_emb);
Py_Initialize();
PyRun_SimpleString("import emb\n"); // (1)
//PyImport_ImportModule("emb"); // (2)
PyRun_SimpleString("print(emb.foo())\n"); // (3)
Py_Finalize();
return 0;
}
I add the emb
module to built-ins of the embedded interpreter.
I'd also like to import it automatically, so users don't have to issue import emb
statement in their scripts supplied to my embedded interpreter.
I'm trying two ways of importing, in lines (1) and (2).
The (1) works and the emb
module can be found without explicit import in the simple test in line (3). However, if I comment out the line (1) and uncomment the line (2) to import with C API of Python 3 call, then the line (3) produces error:
Traceback (most recent call last):
File "<string>", line 1, in <module>
NameError: name 'emb' is not defined
I'd like to understand what is the difference here between the two manners of importing. Do they import module into different namespaces / scopes ?
The Python 3 documentation led me along this path:
__import__()
__import__()
function is invoked by the import statement.Perhaps I made a mistake assuming PyImport_ImportModule
is one-to-one equivalent and I should be using PyImport_ImportModuleEx with correct (which exactly?) globals and locals, so my 'emb' lands in global namespace of my embedded interpreter.
__import__
doesn't put the module in any namespace at all, but returns it instead.
import
calls __import__
, plus it stores the result in a variable.
The docs say that import spam
does something similar to:
spam = __import__('spam', globals(), locals(), [], 0)
To get the same effect in the C API, you need to assign to the emb
global. In other words, set the emb
attribute on the __main__
module.
PyObject* emb_module = PyImport_ImportModule("emb");
PyObject* main_module = PyImport_AddModule("__main__");
PyObject_SetAttrString(main_module, "emb", emb_module);
Py_XDECREF(emb_module);
/* (main_module is a borrowed reference) */