Python在函数级与模块级导入
如果有疑问,我通常会将导入语句放在模块的顶部。通常,这会减少重复,这很好。但是,在只有一个函数(或类)需要导入的情况下,是否存在性能下降 以下内容是否仅在调用函数时导入Python在函数级与模块级导入,python,import,scope,Python,Import,Scope,如果有疑问,我通常会将导入语句放在模块的顶部。通常,这会减少重复,这很好。但是,在只有一个函数(或类)需要导入的情况下,是否存在性能下降 以下内容是否仅在调用函数时导入 def func(): from task import test 如果是这样,我想这可能是一个轻微的效率。我还假设您可以获得一些附加点,以加快垃圾收集和变量作用域,因为导入的对象不会添加到全局字典中。正如另一张海报所说: 这主要是由于变量查找。在全局范围内查找变量需要字典查找。相反,编译器静态地确
def func():
from task import test
如果是这样,我想这可能是一个轻微的效率。我还假设您可以获得一些附加点,以加快垃圾收集和变量作用域,因为导入的对象不会添加到全局字典中。正如另一张海报所说:
这主要是由于变量查找。在全局范围内查找变量需要字典查找。相反,编译器静态地确定本地名称,并通过索引引用它们,因此不需要查找字典
这些假设是否合理?我是否完全偏离了基准
谢谢让我们看看以下两个函数的字节码:
def func1():
""" test imported each time function is run """
from task import test
test()
def func2():
""" test was imported at top of module """
test()
如下所示,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
正如德尔南在评论中指出的那样,预先考虑到这一点可能是过早的优化
至于
test
位于全局命名空间中,这不太可能导致任何查找性能问题。我认为您可以看到这一点的最显著方式是,如果test
与您经常使用的另一个名称发生哈希冲突,这会导致查找第二个名称的时间更长。再次,过早的优化来考虑前面的罕见情况。< P>我认为如果不经常调用,将导入放在定义中是有意义的。 < P>函数中的导入仅在函数运行时才导入。请记住,在Python中,所有语句都是在遇到它们时执行的,导入语句与其他语句一样。顶级导入是在导入模块时导入的,因为它们是模块中的顶级语句
您对名称查找的担忧是错误的:差异可以忽略不计,只有在分析显示问题时才应该考虑
我只将模块导入到函数范围中有两个原因:1)修复循环导入问题,顺便说一句,这可能可以通过重构以其他方式解决;或者2)如果模块是可选的,并且函数没有被我的许多用户使用。在2)的情况下,模块可能完全丢失,除非有人调用该函数,否则不会出现问题。至于名称查找性能:这无关紧要。在极少数情况下,它会这样做,你会发现当你完成代码,发现它太慢,并分析。但请注意,它实际上不会导入模块不止一次-它只是检查是否是必须的,每次调用它。感谢你这样布置它;这很有用。不熟悉dis库。这更多的是一个理论问题。似乎有区别,即使可以忽略。谢谢,内德,这是最有吸引力的方式吗?我看到一些人在模块根目录的init.py上进行导入,然后从那里导入所有内容。这可以用来解决某些循环进口问题吗?
>>> 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