Import模块分析

>>> dis.dis(compile("import os", "<none>", "exec"))
  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (os)
              9 STORE_NAME               0 (os)
             12 LOAD_CONST               1 (None)
             15 RETURN_VALUE

Python/ceval.c
==============

case IMPORT_NAME:
    w = GETITEM(names, oparg);

    // 取__import__这个builtin函数
    x = PyDict_GetItemString(f->f_builtins, "__import__");
    if (x == NULL) {
        PyErr_SetString(PyExc_ImportError,
                        "__import__ not found");
        break;
    }
    Py_INCREF(x);

    // 打包参数
    v = POP();
    u = TOP();
    if (PyInt_AsLong(u) != -1 || PyErr_Occurred())
        w = PyTuple_Pack(5,
                    w,
                    f->f_globals,
                    f->f_locals == NULL ?
                          Py_None : f->f_locals,
                    v,
                    u);
    else
        w = PyTuple_Pack(4,
                    w,
                    f->f_globals,
                    f->f_locals == NULL ?
                          Py_None : f->f_locals,
                    v);
    Py_DECREF(v);
    Py_DECREF(u);
    if (w == NULL) {
        u = POP();
        Py_DECREF(x);
        x = NULL;
        break;
    }
    READ_TIMESTAMP(intr0);

    // 调用__import__函数
    // __import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module
    v = x;
    x = PyEval_CallObject(v, w);
    Py_DECREF(v);
    READ_TIMESTAMP(intr1);
    Py_DECREF(w);
    SET_TOP(x);
    if (x != NULL) continue;
    break;

Python/bltinmodule.c
====================

static PyMethodDef builtin_methods[] = {
    {"__import__",      (PyCFunction)builtin___import__, METH_VARARGS | METH_KEYWORDS, import_doc},
    ...
};

static PyObject *
builtin___import__(PyObject *self, PyObject *args, PyObject *kwds)
{
    static char *kwlist[] = {"name", "globals", "locals", "fromlist",
                             "level", 0};
    char *name;
    PyObject *globals = NULL;
    PyObject *locals = NULL;
    PyObject *fromlist = NULL;
    int level = -1;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|OOOi:__import__",
                    kwlist, &name, &globals, &locals, &fromlist, &level))
        return NULL;

    // ok,import模块的入口
    return PyImport_ImportModuleLevel(name, globals, locals,
                                      fromlist, level);
}

Python/import.c
=================

PyObject *
PyImport_ImportModuleLevel(char *name, PyObject *globals, PyObject *locals,
                         PyObject *fromlist, int level)
{
    PyObject *result;
    _PyImport_AcquireLock();

    // 好吧,这个才是最终的入口
    result = import_module_level(name, globals, locals, fromlist, level);
    if (_PyImport_ReleaseLock() < 0) {
        Py_XDECREF(result);
        PyErr_SetString(PyExc_RuntimeError,
                        "not holding the import lock");
        return NULL;
    }
    return result;
}

static PyObject *
import_module_level(char *name, PyObject *globals, PyObject *locals,
                    PyObject *fromlist, int level)
{
    char buf[MAXPATHLEN+1];
    Py_ssize_t buflen = 0;
    PyObject *parent, *head, *next, *tail;

    if (strchr(name, '/') != NULL
#ifdef MS_WINDOWS
        || strchr(name, '\\') != NULL
#endif
        ) {
        PyErr_SetString(PyExc_ImportError,
                        "Import by filename is not supported.");
        return NULL;
    }

    // 获取import语句所在的package
    parent = get_parent(globals, buf, &buflen, level);
    if (parent == NULL)
        return NULL;

    head = load_next(parent, level < 0 ? Py_None : parent, &name, buf,
                        &buflen);
    if (head == NULL)
        return NULL;

    tail = head;
    Py_INCREF(tail);
    while (name) {
        next = load_next(tail, tail, &name, buf, &buflen);
        Py_DECREF(tail);
        if (next == NULL) {
            Py_DECREF(head);
            return NULL;
        }
        tail = next;
    }
    if (tail == Py_None) {
        /* If tail is Py_None, both get_parent and load_next found
           an empty module name: someone called __import__("") or
           doctored faulty bytecode */
        Py_DECREF(tail);
        Py_DECREF(head);
        PyErr_SetString(PyExc_ValueError,
                        "Empty module name");
        return NULL;
    }

    if (fromlist != NULL) {
        if (fromlist == Py_None || !PyObject_IsTrue(fromlist))
            fromlist = NULL;
    }

    if (fromlist == NULL) {
        Py_DECREF(tail);
        return head;
    }

    Py_DECREF(head);
    if (!ensure_fromlist(tail, fromlist, buf, buflen, 0)) {
        Py_DECREF(tail);
        return NULL;
    }

    return tail;
}

reload一个模块会复用已经载入的该模块的md_dict。对于pure python的模块,如果要干净 的reload,可以先将该模块从sys.modules中删除。当然这个对于builtin和c module是无效 的。

$ cat foo.py
a = 1
b = 2

print 'foo'

>>> import foo
foo
>>> dir(foo)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'a', 'b']

$cat foo.py
a = 1
c = 2

print 'foo'

>>> reload(foo)
foo
<module 'foo' from 'foo.py'>
>>> dir(foo)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'a', 'b', 'c']

>>> import sys
>>> del sys.modules['foo']
>>> import foo
foo
>>> dir(foo)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'a', 'c']