我该如何使用importlib.LazyLoader?

26

在我的模块中,我有一些依赖于一个启动时间较长的外部模块的函数。 我如何使用LazyLoader? 如果我有

import veggies
或者
import veggies.brussels.sprouts
或者
from veggies.brussels import sprouts

如何使用LazyLoader替换这些语句,以便将模块中的内容延迟到需要时执行?从文档中并不容易看出如何使用它。没有例子,而且nullege代码搜索只能找到Python自带的单元测试。

2个回答

17

原始问题中有些代码似乎是懒加载进行完整导入:

以下文件对两个模块进行了懒加载导入:

import sys
import importlib.util

def lazy(fullname):
  try:
    return sys.modules[fullname]
  except KeyError:
    spec = importlib.util.find_spec(fullname)
    module = importlib.util.module_from_spec(spec)
    loader = importlib.util.LazyLoader(spec.loader)
    # Make module with proper locking and get it inserted into sys.modules.
    loader.exec_module(module)
    return module

os = lazy("os")
myown = lazy("myown")

print(os.name)
myown.test()

为进行测试,我在myown.py中使用了以下内容。

print("Executed myown.")
def test():
  print("OK")

那很好地运作了(Python 3.8a0)。


1
你能展示一下如何实际使用 LadyLoader 的例子吗? - gerrit
1
我建议使用loader = importlib.util.LazyLoader.factory(spec.loader),它还会检查exec_module属性。 - throws_exceptions_at_you
1
另一个示例用例在 https://www.mercurial-scm.org/repo/hg/file/tip/hgdemandimport/demandimportpy3.py 中。 - gps
这似乎适用于 CPython 3.5 到 3.10b4,也许更高版本。 - dstromberg
3
当前的Python文档中有一个片段 - 非常相似!- 可以被认为比这个答案更加规范:https://docs.python.org/3/library/importlib.html#implementing-lazy-imports - creanion
显示剩余5条评论

1
6年后,我正在测试一些懒加载的方法,以便改善应用程序的启动时间,但是PEP690(Python 3.12)还不可用。
在测试懒加载器方法时,请注意Python不会保留该导入,您的懒对象将像其他对象一样被垃圾回收。
以下是一个示例。

lib.py

print('Executing lib.py')


class MyClass():
    def get_name(self):
        return self.__class__.__name__

main.py

def lazy(fullname):
    import sys
    import importlib.util
    try:
        return sys.modules[fullname]
    except KeyError:
        spec = importlib.util.find_spec(fullname)
        module = importlib.util.module_from_spec(spec)
        loader = importlib.util.LazyLoader(spec.loader)
        # Make module with proper locking and get it inserted into sys.modules.
        loader.exec_module(module)
        return module


def method1():
    lib = lazy("lib")
    my_class = lib.MyClass()
    print(my_class.get_name())


def method2():
    import lib
    my_class = lib.MyClass()
    print(my_class.get_name())


if __name__ == '__main__':
    methods = [method1, method2]
    for method in methods:
        print('Executing {}'.format(method.__name__))
        for _ in range(2):
            method()
        print('---------------------------------')

结果:

Executing method1
Executing lib.py
MyClass
Executing lib.py
MyClass
---------------------------------
Executing method2
Executing lib.py
MyClass
MyClass
---------------------------------

看起来PEP 690被拒绝了。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接