Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do PyImport_ImportModule and import statement load into different namespace?

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:

  1. PyImport_ImportModule is best described by referring to the built-in Python function __import__()
  2. __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.

like image 449
mloskot Avatar asked Nov 03 '11 16:11

mloskot


People also ask

What is the correct syntax for importing a module?

The import has the following syntax − import module1 module2 [,... moduleN] When the interpreter encounters an import statement, it imports the module if the module is present in the search path. A search path is a list of directories that the interpreter searches before importing a module.

Which statement is used to import all submodules from a module?

The "from module import *" statement is used to import all submodules from a Python package/module. For example, if you want to import all modules from your module (say nyModule) and do not want to prefix "myModule."

How to import modules in Python?

Let’s learn about the different ways to import modules in python. A module is a file containing Python definitions and statements. The file name is the module name with the suffix .py appended. Modules provide the reusability of code. By using modules, we can group related code. — python docs

What is the from-import statement in Python?

The from...import Statement. Python's from statement lets you import specific attributes from a module into the current namespace. The from...import has the following syntax −. from modname import name1 [, name2 [, ... nameN]] For example, to import the function fibonacci from the module fib, use the following statement −.


1 Answers

__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) */
like image 142
Petr Viktorin Avatar answered Sep 28 '22 17:09

Petr Viktorin