1

在我的应用程序中,我有:

...
folder_a/
    __init__.py
    a.py
    folder_b/
        __init__.py
        b1.py 
        b2.py
        ...

我需要根据一个变量从 动态加载模块,folder_b比如. 为此,在 中,我这样做:a.pymodule_from_ba.py

mymodule = __import__("folder_b.%s" % module_from_b, globals(), locals(), fromlist=["*"])

由于这将存在于一个循环中,即被多次调用,我想知道它是否对性能有任何影响,或者其他什么?如果是这样,有没有办法在保留动态模块加载能力的同时减轻它?

4

3 回答 3

1

我从来没有对它进行基准测试,但我相信导入(无论是动态的还是静态的)一个之前已经导入正在运行的解释器(即使是完全不相关的代码)的模块应该非常便宜。它真正要做的应该是一些(成功的)字典查找。

导入一个新模块当然会运行模块中的所有代码,加上文件系统搜索来找到它。

因此,如果您从一组相对较小的模块中重复导入动态选择的模块,那么只要您可以容忍第一次使用每个特定模块时的延迟(多少延迟取决于您的模块);过了一会儿,几乎所有你要导入的模块都已经被导入了,所以__import__调用会变得很便宜。

您可能会考虑另一种设计:如果您需要的总模块集是预先知道的(静态或动态),您可以在循环之前预导入它们以“预热”Python 的导入模块集。如果 b 中没有很多不会使用的模块,您可以导入 b's 中的所有内容__init__.py

这样,导入延迟将在启动时得到解决,您可以getattr在 b 包上使用来动态获取您的模块,而不是需要使用__import__. 如果您要加载如此多的模块以至于您在循环中分散导入成本,或者如果您有很多模块但只需要相对较少的数量并且很难知道哪些模块在前面,那么这不是一个好的选择时间。

还有另一种可能更好的方法,如果在您确定要导入哪个模块的地方选择一些常量字符串(而不是从配置文件或用户输入中读取的内容),则该方法将起作用。与其将模块的名称向前传递以最终在其他地方导入,为什么不在那里导入模块并将模块本身传递给最终在其他地方使用呢?作为一个虚构的例子,因为我不知道你在做什么,而不是:

for module_name in ['b1', 'b2', 'b3', 'b4']:
    function_using_module(module_name)

def function_using_module(module_name):
    module = __import__(...)
    ...

你可以这样做:

from folder_b import b1, b2, b3, b4

for module in [b1, b2, b3, b4]:
    function_using_module(module)

def function_using_module(module):
    ...

模块和其他任何东西一样都是对象,因此您可以将它们存储在列表或对象中,或者您对名称所做的任何事情中。直接传递模块通常比传递名称作为模块的代理然后导入它们更干净。

于 2012-05-23T21:48:25.017 回答
0

它完全没有区别 import 语句__import__()在字节码中表示为调用。以下两个是等价的。

import spam
spam = __import__('spam', globals(), locals(), [], -1)
于 2012-05-24T00:04:43.493 回答
-1

如果您可能会多次执行此操作,为什么不检查该模块是否已存在于您当前的命名空间中,如果不存在则导入它。

if 'module_I_need_to_load' not in dir():
    from b import module_I_need_to_load
# Or you can look in vars() instead if you have a
# hell of a lot of modules loaded up as dir is a 
# list and vars is a dictionary which will have a
# faster lookup time when you start having a lot of
# elements
if 'module_I_need_to_load' not in vars():
    from b import module_I_need_to_load
于 2012-05-23T20:07:30.180 回答