[issue22557] Local import is too slow

Serhiy Storchaka report at bugs.python.org
Sun Oct 5 16:26:34 CEST 2014


Serhiy Storchaka added the comment:

I'm not experienced in import machinery. Here is preliminary patch which 
implements my idea for particular case.

Performance effect is almost so good as manual caching in a global.

>>> import timeit
>>> def f():
...      import locale
... 
>>> min(timeit.repeat(f, number=100000, repeat=10))
0.09563599999819417

Of course it breaks tests.

> It's possible there is room for other optimisations that don't break the
> import override semantics (such as a fast path for when __import__ is the
> standard import function).

Good idea.

----------
keywords: +patch
Added file: http://bugs.python.org/file36814/faster_import.patch

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue22557>
_______________________________________
-------------- next part --------------
diff -r 85de13b746ac Lib/test/test_import.py
--- a/Lib/test/test_import.py	Sat Oct 04 16:09:02 2014 +0300
+++ b/Lib/test/test_import.py	Sun Oct 05 17:15:42 2014 +0300
@@ -312,7 +312,7 @@ class ImportTests(unittest.TestCase):
 
     @cpython_only
     def test_delete_builtins_import(self):
-        args = ["-c", "del __builtins__.__import__; import os"]
+        args = ["-c", "del __builtins__.__import__; import this"]
         popen = script_helper.spawn_python(*args)
         stdout, stderr = popen.communicate()
         self.assertIn(b"ImportError", stdout)
diff -r 85de13b746ac Python/ceval.c
--- a/Python/ceval.c	Sat Oct 04 16:09:02 2014 +0300
+++ b/Python/ceval.c	Sun Oct 05 17:15:42 2014 +0300
@@ -2464,16 +2464,42 @@ PyEval_EvalFrameEx(PyFrameObject *f, int
         TARGET(IMPORT_NAME) {
             _Py_IDENTIFIER(__import__);
             PyObject *name = GETITEM(names, oparg);
-            PyObject *func = _PyDict_GetItemId(f->f_builtins, &PyId___import__);
+            PyObject *func;
             PyObject *from, *level, *args, *res;
+            from = POP();
+            level = TOP();
+            if (from == Py_None && PyUnicode_Check(name)) {
+                if (PyLong_AsLong(level) == 0) {
+                    Py_ssize_t i = PyUnicode_FindChar(name, '.',
+                                        0, PyUnicode_GET_LENGTH(name), 1);
+                    if (i == -1) {
+                        res = PyDict_GetItem(PyImport_GetModuleDict(), name);
+                        if (res != NULL) {
+                            Py_INCREF(res);
+                            Py_DECREF(level);
+                            Py_DECREF(from);
+                            SET_TOP(res);
+                            DISPATCH();
+                        }
+                    }
+                    else if (i == -2) {
+                        Py_DECREF(level);
+                        Py_DECREF(from);
+                        STACKADJ(-1);
+                        goto error;
+                    }
+                }
+                else if (PyErr_Occurred())
+                    PyErr_Clear();
+            }
+            func = _PyDict_GetItemId(f->f_builtins, &PyId___import__);
             if (func == NULL) {
                 PyErr_SetString(PyExc_ImportError,
                                 "__import__ not found");
+                STACKADJ(-1);
                 goto error;
             }
             Py_INCREF(func);
-            from = POP();
-            level = TOP();
             if (PyLong_AsLong(level) != -1 || PyErr_Occurred())
                 args = PyTuple_Pack(5,
                             name,


More information about the Python-bugs-list mailing list