为什么从模块导入函数比整个模块本身需要更长的时间? [英] Why does it take longer to import a function from a module than the entire module itself?

查看:43
本文介绍了为什么从模块导入函数比整个模块本身需要更长的时间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑:

<预><代码>>>>timeit.timeit('from win32com.client import Dispatch', number=100000)0.18883283882571789>>>timeit.timeit('导入 win32com.client', number=100000)0.1275979248277963

仅导入 Dispatch 函数而不是整个模块需要更长的时间,这似乎违反直觉.有人可以解释为什么采用单个函数的开销如此之大吗?谢谢!

解决方案

那是因为:

from win32com.client import Dispatch

相当于:

import win32com.client #先导入整个模块Dispatch = win32com.client.Dispatch #将需要的属性赋值给全局变量del win32com #删除对模块对象的引用

<小时>

但是 from win32com.client import Dispatch 有其自身的优势,例如如果您在代码中多次使用 win32com.client.Dispatch 那么最好将它分配给一个变量,这样可以减少查找次数.否则每次调用 win32com.client.Dispatch() 都会先搜索 win32com,然后在 win32com 中搜索 client,最后在 win32com.clientDispatch.

<小时>

字节码比较:

从字节码可以明显看出,from os.path import splitext 所需的步骤数比简单的import 要多.

<预><代码>>>>def func1():从 os.path 导入 splittext...>>>def func2():导入 os.path...>>>导入文件>>>dis.dis(func1)2 0 LOAD_CONST 1 (-1)3 LOAD_CONST 2 (('splitext',))6 IMPORT_NAME 0 (os.path)9 IMPORT_FROM 1(拆分文本)12 STORE_FAST 0(拆分文本)15 POP_TOP16 LOAD_CONST 0 (无)19 RETURN_VALUE>>>dis.dis(func2)2 0 LOAD_CONST 1 (-1)3 LOAD_CONST 0(无)6 IMPORT_NAME 0 (os.path)9 STORE_FAST 0 (操作系统)12 LOAD_CONST 0 (无)15 RETURN_VALUE

<小时>

模块缓存:

注意在from os.path import splitext之后你仍然可以使用sys.modules访问os模块,因为python缓存了导入的模块.

来自文档:

<块引用>

注意出于效率原因,每个模块每次只导入一次口译员会议.因此,如果你改变你的模块,你必须重新启动解释器——或者,如果它只是你想测试的一个模块交互地,使用 reload(),例如reload(modulename).

演示:

导入系统从 os.path 导入 splittext尝试:打印操作系统除了名称错误:打印找不到操作系统"尝试:打印 os.path除了名称错误:打印找不到 os.path"打印 sys.modules['os']

输出:

os 未找到找不到 os.path<来自'/usr/lib/python2.7/os.pyc'的模块'os'>

时间比较:

$ python -m timeit -n 1 'from os.path import splitext'1 个循环,最好的 3 个:每个循环 5.01 微秒$ python -m timeit -n 1 'import os.path'1 个循环,最好的 3 个:每个循环 4.05 微秒$ python -m timeit -n 1 '从操作系统导入路径'1 个循环,最好的 3 个:每个循环 5.01 微秒$ python -m timeit -n 1 'import os'1 个循环,最好的 3 个:每个循环 2.86 微秒

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!

解决方案

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

这篇关于为什么从模块导入函数比整个模块本身需要更长的时间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆