Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does it take longer to import a function from a module than the entire module itself?

Tags:

Consider:

>>> timeit.timeit('from win32com.client import Dispatch', number=100000) 0.18883283882571789 >>> timeit.timeit('import win32com.client', number=100000) 0.1275979248277963 

It takes significantly longer to import only the Dispatch function rather than the entire module, which seems counter intuitive. Could someone explain why the overhead for taking a single function is so bad? Thanks!

like image 587
TheoretiCAL Avatar asked Jul 12 '13 00:07

TheoretiCAL


People also ask

What is the difference between import module and from module import *?

The difference between import and from import in Python is: import imports the whole library. from import imports a specific member or members of the library.

What is the difference between import and from?

Explain the difference between import and from import statement, with example. It import entire module and so everything inside the module will be imported like functions, constant, variables. from <module> import statement imports selected items , but to use these items we don't have to prefix module name.

What happens when you import a module Python?

When a module is first imported, Python searches for the module and if found, it creates a module object 1, initializing it. If the named module cannot be found, a ModuleNotFoundError is raised. Python implements various strategies to search for the named module when the import machinery is invoked.

When importing a module into a Python program What is the difference between using the import statement and using the From statement?

The import statement allows you to import all the functions from a module into your code. Often, though, you'll only want to import a few functions, or just one. If this is the case, you can use the from statement. This lets you import only the exact functions you are going to be using in your code.


2 Answers

That's because:

from win32com.client import Dispatch 

is equivalent to:

import win32com.client              #import the whole module first Dispatch = win32com.client.Dispatch #assign the required attributes to global variables del win32com                        #remove the reference to module object 

But from win32com.client import Dispatch has its own advantages, for example if you're using win32com.client.Dispatch multiple times in your code then it's better to assign it to a variable, so that number of lookups can be reduced. Otherwise each call to win32com.client.Dispatch() will first search search for win32com and then client inside win32com, and finally Dispatch inside win32com.client.


Byte-code comparison:

From the byte code it is clear that number of steps required for from os.path import splitext are greater than the simple import.

>>> def func1():     from os.path import splitext ...      >>> def func2():     import os.path ...      >>> import dis >>> dis.dis(func1)   2           0 LOAD_CONST               1 (-1)               3 LOAD_CONST               2 (('splitext',))               6 IMPORT_NAME              0 (os.path)               9 IMPORT_FROM              1 (splitext)              12 STORE_FAST               0 (splitext)              15 POP_TOP                           16 LOAD_CONST               0 (None)              19 RETURN_VALUE         >>> dis.dis(func2)   2           0 LOAD_CONST               1 (-1)               3 LOAD_CONST               0 (None)               6 IMPORT_NAME              0 (os.path)               9 STORE_FAST               0 (os)              12 LOAD_CONST               0 (None)              15 RETURN_VALUE      

Module caching:

Note that after from os.path import splitext you can still access the os module using sys.modules because python caches the imported modules.

From docs:

Note For efficiency reasons, each module is only imported once per interpreter session. Therefore, if you change your modules, you must restart the interpreter – or, if it’s just one module you want to test interactively, use reload(), e.g. reload(modulename).

Demo:

import sys from os.path import splitext try:     print os except NameError:     print "os not found" try:     print os.path except NameError:     print "os.path is not found"  print sys.modules['os'] 

output:

os not found os.path is not found <module 'os' from '/usr/lib/python2.7/os.pyc'> 

Timing comparisons:

$ python -m timeit -n 1 'from os.path import splitext' 1 loops, best of 3: 5.01 usec per loop $ python -m timeit -n 1 'import os.path' 1 loops, best of 3: 4.05 usec per loop $ python -m timeit -n 1 'from os import path' 1 loops, best of 3: 5.01 usec per loop $ python -m timeit -n 1 'import os' 1 loops, best of 3: 2.86 usec per loop 
like image 56
Ashwini Chaudhary Avatar answered Nov 06 '22 06:11

Ashwini Chaudhary


The entire module still has to be imported to get the name you want from it...You'll also find that the OS is caching the module so subsequent access to the .pyc file will be quicker.

like image 42
Jon Clements Avatar answered Nov 06 '22 08:11

Jon Clements