Python导入编码sty

2024-04-20 04:55:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我发现了一种新的模式。这种模式是众所周知的还是有什么看法?

基本上,我很难清理上下源文件,以确定哪些模块导入是可用的等等,所以现在,代替

import foo
from bar.baz import quux

def myFunction():
    foo.this.that(quux)

我将所有导入移到实际使用它们的函数中,如下所示:

def myFunction():
    import foo
    from bar.baz import quux

    foo.this.that(quux)

这可以做一些事情。首先,我很少意外地用其他模块的内容污染我的模块。我可以为模块设置__all__变量,但随后我必须随着模块的发展而更新它,这无助于实际存在于模块中的代码的命名空间污染。

其次,我很少在模块的顶部出现一连串的导入,其中一半或更多我不再需要,因为我已经重构了它。最后,我发现这个模式更容易阅读,因为每个引用的名称都在函数体中。


Tags: 模块函数fromimportthatfoodef模式
3条回答

这个问题的top-voted answer格式很好,但在性能方面绝对错误。让我示范一下

性能

顶级进口

import random

def f():
    L = []
    for i in xrange(1000):
        L.append(random.random())


for i in xrange(1000):
    f()

$ time python import.py

real        0m0.721s
user        0m0.412s
sys         0m0.020s

导入函数体

def f():
    import random
    L = []
    for i in xrange(1000):
        L.append(random.random())

for i in xrange(1000):
    f()

$ time python import2.py

real        0m0.661s
user        0m0.404s
sys         0m0.008s

如您所见,在函数中导入模块可以更有效。原因很简单。它将引用从全局引用移动到本地引用。这意味着,至少对于CPython,编译器将发出LOAD_FAST指令,而不是LOAD_GLOBAL指令。顾名思义,这些速度更快。另一个回答者通过在循环的每一次迭代中导入,人为地提高了查找sys.modules的性能。

通常,最好在顶部导入,但如果您多次访问该模块,则性能是而不是的原因。原因是可以更容易地跟踪模块所依赖的内容,并且这样做与Python世界的大多数其他部分是一致的。

这确实有一些缺点。

测试

如果您希望通过运行时修改来测试模块,那么这可能会使测试变得更加困难。而不是做

import mymodule
mymodule.othermodule = module_stub

你必须这么做

import othermodule
othermodule.foo = foo_stub

这意味着您必须全局地修补othermodule,而不是仅仅更改mymodule中的引用所指向的内容。

依赖项跟踪

这使得模块所依赖的模块不明显。如果您使用许多第三方库或正在重新组织代码,这尤其令人恼火。

我不得不维护一些遗留代码,在所有地方都使用内联导入,这使得代码极难重构或重新打包。

业绩说明

由于python缓存模块的方式,性能没有受到影响。事实上,由于模块位于本地命名空间中,因此在函数中导入模块对性能有轻微的好处。

顶级进口

import random

def f():
    L = []
    for i in xrange(1000):
        L.append(random.random())

for i in xrange(10000):
    f()


$ time python test.py 

real   0m1.569s
user   0m1.560s
sys    0m0.010s

导入函数体

def f():
    import random
    L = []
    for i in xrange(1000):
        L.append(random.random())

for i in xrange(10000):
    f()

$ time python test2.py

real    0m1.385s
user    0m1.380s
sys     0m0.000s

这种方法有几个问题:

  • 当打开它所依赖的模块时,并不是很明显。
  • 它将混淆必须分析依赖关系的程序,例如py2exepy2app
  • 你在许多函数中使用的模块呢?您要么会得到大量的冗余导入,要么必须在文件的顶部有一些导入和一些内部函数。

所以。。。首选方法是将所有导入放在文件的顶部。我发现,如果很难跟踪我的导入,通常意味着我有太多的代码,最好将其拆分为两个或更多文件。

在某些情况下,我发现函数内部的导入非常有用:

  • 处理循环依赖关系(如果您真的无法避免它们)
  • 平台特定代码

另外:将导入放在每个函数中实际上比放在文件顶部要慢得多。第一次加载每个模块时,它被放入sys.modules,而随后的每个导入只花费查找该模块的时间,这相当快(它不会重新加载)。

相关问题 更多 >