PEP 8规定:

导入总是放在文件的顶部,就在任何模块注释和文档字符串之后,在模块全局变量和常量之前。

然而,如果我导入的类/方法/函数只在很少的情况下使用,那么在需要时进行导入肯定会更有效吗?

这不是:

class SomeClass(object):

    def not_often_called(self)
        from datetime import datetime
        self.datetime = datetime.now()

比这更有效率?

from datetime import datetime

class SomeClass(object):

    def not_often_called(self)
        self.datetime = datetime.now()

当前回答

虽然PEP鼓励在模块顶部导入,但在其他级别导入并不会出错。这表明进口应该在顶部,但也有例外。

在使用模块时加载模块是一种微优化。导入缓慢的代码可以在以后进行优化,如果这会产生相当大的差异的话。

不过,您可以在尽可能靠近顶部的位置引入标志,以便有条件地导入,允许用户使用配置导入所需的模块,同时仍然立即导入所有内容。

尽快导入意味着如果任何导入(或导入的导入)缺失或有语法错误,程序将失败。如果所有导入都发生在所有模块的顶部,则python分两步工作。编译。运行。

内置模块可以在任何导入它们的地方工作,因为它们设计得很好。您编写的模块应该是相同的。将导入移动到顶部或它们的第一次使用位置有助于确保没有副作用,并且代码正在注入依赖项。

无论您是否将导入放在顶部,当导入放在顶部时,代码都应该仍然可以工作。所以从立即导入开始,然后根据需要进行优化。

其他回答

当函数被调用0次或1次时,第一种变体确实比第二种更有效。然而,对于第二次和后续调用,“导入每个调用”方法实际上效率较低。请参阅此链接,了解一种通过“惰性导入”将两种方法的优点结合起来的惰性加载技术。

但除了效率之外,还有其他原因可以解释为什么你会更喜欢其中一种。一种方法是让阅读代码的人更清楚地了解这个模块所具有的依赖关系。它们也有非常不同的失败特征——如果没有“datetime”模块,第一个将在加载时失败,而第二个直到方法被调用才会失败。

补充说明:在IronPython中,导入可能比在CPython中要昂贵一些,因为代码基本上是在导入时被编译的。

这是一个只有程序员才能决定的权衡。

Case 1在需要时才导入datetime模块(并进行任何可能需要的初始化),从而节省了一些内存和启动时间。请注意,“仅在被调用时”导入也意味着“每次被调用时”导入,因此第一次调用之后的每个调用仍然会产生执行导入的额外开销。

情况2通过提前导入datetime来节省一些执行时间和延迟,这样在调用not_often_called()时就会更快地返回,而且也不会在每次调用时都产生导入的开销。

除了效率,如果import语句是…前面。将它们隐藏在代码中会使查找某个组件所依赖的模块变得更加困难。

就我个人而言,我通常遵循PEP,除了单元测试之类的东西,我不希望总是加载这些东西,因为我知道除了测试代码之外,它们不会被使用。

这就像许多其他优化一样——你牺牲了一些可读性来换取速度。正如John提到的,如果您已经完成了分析作业,并且发现这是一个非常有用的更改,并且您需要额外的速度,那么就去做吧。最好把所有其他的导入都放在一起:

from foo import bar
from baz import qux
# Note: datetime is imported in SomeClass below

Module initialization only occurs once - on the first import. If the module in question is from the standard library, then you will likely import it from other modules in your program as well. For a module as prevalent as datetime, it is also likely a dependency for a slew of other standard libraries. The import statement would cost very little then since the module intialization would have happened already. All it is doing at this point is binding the existing module object to the local scope.

将这些信息与可读性参数结合起来,我会说import语句最好在模块范围内。

在函数中导入变量/局部作用域可以提高性能。这取决于函数中导入对象的使用情况。如果你多次循环并访问一个模块全局对象,将它导入为本地会有帮助。

test.py

X=10
Y=11
Z=12
def add(i):
  i = i + 10

runlocal.py

from test import add, X, Y, Z

    def callme():
      x=X
      y=Y
      z=Z
      ladd=add 
      for i  in range(100000000):
        ladd(i)
        x+y+z

    callme()

run.py

from test import add, X, Y, Z

def callme():
  for i in range(100000000):
    add(i)
    X+Y+Z

callme()

在Linux上的时间显示了一个小的增益

/usr/bin/time -f "\t%E real,\t%U user,\t%S sys" python run.py 
    0:17.80 real,   17.77 user, 0.01 sys
/tmp/test$ /usr/bin/time -f "\t%E real,\t%U user,\t%S sys" python runlocal.py 
    0:14.23 real,   14.22 user, 0.01 sys

真实的是挂钟。用户是程序中的时间。Sys是系统调用的时间。

https://docs.python.org/3.5/reference/executionmodel.html#resolution-of-names