Python中使用import X或者from X import Y?(性能)

41

如果我要使用至少两种方法的库,下面两种方式的性能和内存使用有区别吗?

from X import method1, method2

并且。
import X
4个回答

52

两者有所不同,因为使用import x版本时需要进行两次名称查找:一次是模块名的查找,另一次是函数名的查找;而使用from x import y则只需要一次查找。

您可以使用dis模块清楚地看到这一点:

import random
def f_1():
    random.seed()

dis.dis(f_1)
     0 LOAD_GLOBAL              0 (random)
     3 LOAD_ATTR                0 (seed)
     6 CALL_FUNCTION            0
     9 POP_TOP
    10 LOAD_CONST               0 (None)
    13 RETURN_VALUE

from random import seed

def f_2():
    seed()

dis.dis(f_2)
     0 LOAD_GLOBAL              0 (seed)
     3 CALL_FUNCTION            0
     6 POP_TOP
     7 LOAD_CONST               0 (None)
    10 RETURN_VALUE

如你所见,使用形式为from x import y的表单会更快一些。

另一方面,import xfrom x import y较便宜,因为少了一个名称查找。让我们看看反汇编代码:

def f_3():
    import random

dis.dis(f_3)
     0 LOAD_CONST               1 (-1)
     3 LOAD_CONST               0 (None)
     6 IMPORT_NAME              0 (random)
     9 STORE_FAST               0 (random)
    12 LOAD_CONST               0 (None)
    15 RETURN_VALUE

def f_4():
    from random import seed

dis.dis(f_4)
     0 LOAD_CONST               1 (-1)
     3 LOAD_CONST               2 (('seed',))
     6 IMPORT_NAME              0 (random)
     9 IMPORT_FROM              1 (seed)
    12 STORE_FAST               0 (seed)
    15 POP_TOP
    16 LOAD_CONST               0 (None)
    19 RETURN_VALUE

我不知道原因,但似乎表单from x import y看起来像一个函数调用,因此比预期更加耗费资源。因此,如果导入的函数只使用一次,那么使用import x会更快,而如果使用超过一次,则使用from x import y更快。

话虽如此,像往常一样,我建议你不要根据这种知识决定如何导入模块和函数,因为这只是一些过早的优化。
个人认为,在许多情况下,显式命名空间更易读,我建议您做同样的事情:使用自己的美学感觉 :-)


1
@sdolan:你的timeit结果似乎表明import xfrom x import y更快,这似乎与查看dis.dis后的预期相反。相当好奇。 - unutbu
1
更新:这里有一些 timeit 结果,证明 from x import y 更快(p 别名为 python2.6): p -m timeit "import random; random.seed()" 10000 次循环,3次中的最佳结果:每次27.7微秒。 p -m timeit "from random import seed; seed()" 10000 次循环,3次中的最佳结果:每次29.2微秒。在 3.1 中进行相同的测试,结果类似。 - Sam Dolan
17
这是虚拟机上的一个操作码。如果需要10个周期,那在2G赫兹的电脑上就是5纳秒。仅阅读这个句子所需的时间比该程序节省你一生的时间还要多。 - Jochen Ritzel
我已经添加了对sdolan发现原因的分析。 - rob
一个 C 模块和一个纯 Python 模块会有什么区别吗? - OTZ
显示剩余5条评论

11

没有内存或速度上的区别(因为整个模块都必须进行评估,因为最后一行代码可能是Y = something_else)。除非你的电脑是20世纪80年代的,否则无论如何都不重要。


3
在我的项目中,从PyQt5进行40次导入会导致启动时500毫秒的延迟,我觉得这是不可接受的。这是在SSD和i7-4790K上的情况。因此,我可能会转向C++,所以是的,这很重要...也许不完全符合OP问题的背景,但它确实显示了导入可能会导致性能问题。 - rr-
@rr- Shed Skin,Cython或Nuitka都可以将Python编译为C。 - Cees Timmerman

9
如果您在一个循环中多次调用函数(数百万次或更多),双重字典查找将会累加,这是需要注意的。下面的示例显示了20%的增加。
所引用的时间是基于Python 3.4在Win7 64位机器上的。(对于Python 2.7,请将range命令更改为xrange)。
此示例高度基于书籍High Performance Python,尽管他们关于本地函数查找更好的第三个示例似乎不再适用于我。
import math
from math import sin

def tight_loop_slow(iterations):
    """
    >>> %timeit tight_loop_slow(10000000)
    1 loops, best of 3: 3.2 s per loop
    """
    result = 0
    for i in range(iterations):
        # this call to sin requires two dictionary lookups
        result += math.sin(i)

def tight_loop_fast(iterations):
    """
    >>> %timeit tight_loop_fast(10000000)
    1 loops, best of 3: 2.56 s per loop
    """
    result = 0
    for i in range(iterations):
        # this call to sin only requires only one lookup
        result += sin(i)

7
我不认为有任何真正的区别,通常担心那么少的内存并不值得。如果你将会考虑到内存问题,它很可能更多地出现在你的代码中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接