Ben*_*Ben 8 python import scope
如有疑问,我通常会将导入语句放在模块的顶部.通常,这会减少重复,这很好.但是,在只有一个函数(或类)需要导入的情况下,是否存在性能下降?
在调用函数时,是否只导入以下内容?
def func():
from task import test
Run Code Online (Sandbox Code Playgroud)
如果是这样,我想这可能是一个微小的效率.我还假设你可以为更快的垃圾收集和变量作用域获得一些附加点,因为导入的对象不会被添加到全局字典中.正如另一张海报很好地说:
这主要是由于查找变量.查找全局范围中的变量需要查找字典.相反,编译器静态地确定本地名称并通过索引引用它们,因此不需要查找字典.
那些公平的假设是我完全偏离基础吗?
谢谢
仅在函数运行时导入函数中的导入.请记住,在Python中,所有语句在遇到它们时都会执行,而导入语句就像其他任何语句一样.导入模块时会导入顶级导入,因为它们是模块中的顶级语句.
您对名称查找的担忧是错误的:差异可以忽略不计,只有在分析显示问题时才应考虑.
我只将模块导入函数作用域有两个原因:1)修复循环导入问题,可能通过重构以其他方式解决,或者2)如果模块是可选的,并且许多函数没有使用我的用户.在2)的情况下,模块可以完全丢失,除非有人调用该函数,否则不会出现问题.
让我们看看以下两个函数的字节码是什么样的:
def func1():
""" test imported each time function is run """
from task import test
test()
def func2():
""" test was imported at top of module """
test()
Run Code Online (Sandbox Code Playgroud)
如下所示,func2()使用全局导入的函数可以节省大量步骤test。
>>> dis.dis(func1)
3 0 LOAD_CONST 1 (-1)
3 LOAD_CONST 2 (('test',))
6 IMPORT_NAME 0 (task)
9 IMPORT_FROM 1 (test)
12 STORE_FAST 0 (test)
15 POP_TOP
4 16 LOAD_FAST 0 (test)
19 CALL_FUNCTION 0
22 POP_TOP
23 LOAD_CONST 3 (None)
26 RETURN_VALUE
>>> dis.dis(func2)
3 0 LOAD_GLOBAL 0 (test)
3 CALL_FUNCTION 0
6 POP_TOP
7 LOAD_CONST 1 (None)
10 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
正如 delnan 的评论中指出的那样,预先考虑到这一点可能是不成熟的优化。
至于test位于全局命名空间中,这不太可能导致任何查找性能问题。我认为您可以看到这一点的最值得注意的方式是,如果您经常使用的另一个名称存在哈希冲突test,这会导致第二个名称的查找时间更长。再次强调,过早的优化需要预先考虑这种罕见的情况。