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:
- PyImport_ImportModule is best described by referring to the built-in Python function
__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.importcalls__import__, plus it stores the result in a variable.The docs say that
import spamdoes something similar to:To get the same effect in the C API, you need to assign to the
embglobal. In other words, set theembattribute on the__main__module.