详解Python如何实现惰性导入-lazy import

 更新时间:2022年10月18日 10:08:44   作者:somenzz  
如果你的 Python 程序程序有大量的 import,而且启动非常慢,那么你应该尝试懒导入,本文分享一种实现惰性导入的一种方法,需要的可以参考一下

前言

如果你的 Python 程序程序有大量的 import,而且启动非常慢,那么你应该尝试懒导入,本文分享一种实现惰性导入的一种方法。虽然PEP0690已经提案让 Python 编译器(-L) 或者标准库加入这个功能,但目前的 Python 版本还未实现。

众所周知,Python 应用程序在执行用户的实际操作之前,会执行 import 操作,不同的模块可能来自不同的位置,某些模块的运行可能非常耗时,某些模块可能根本不会被用户调用,因此很多模块的导入纯粹是浪费时间。

因此我们需要惰性导入,当应用惰性导入时,运行 import foo 仅仅会把名字 foo 添加到全局的全名空间(globals())中作为一个懒引用(lazy reference),编译器遇到任何访问 foo 的代码时才会执行真正的 import 操作。类似的,from foo import bar 会把 bar 添加到命名空间,当遇到调用 bar 的代码时,就把 foo 导入。

写代码实现

那怎么写代码实现呢?其实不必写代码实现,已经有项目实现了懒导入功能,那就是 TensorFlow,它的代码并没有任何三方库依赖,我把它放到这里,以后大家需要懒导入的时候直接把LazyLoader类复制到自己的项目中去即可。

源代码如下:

# Code copied from https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/util/lazy_loader.py
"""A LazyLoader class."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import importlib
import types


class LazyLoader(types.ModuleType):
  """Lazily import a module, mainly to avoid pulling in large dependencies.

  `contrib`, and `ffmpeg` are examples of modules that are large and not always
  needed, and this allows them to only be loaded when they are used.
  """

  # The lint error here is incorrect.
  def __init__(self, local_name, parent_module_globals, name):  # pylint: disable=super-on-old-class
    self._local_name = local_name
    self._parent_module_globals = parent_module_globals

    super(LazyLoader, self).__init__(name)

  def _load(self):
    # Import the target module and insert it into the parent's namespace
    module = importlib.import_module(self.__name__)
    self._parent_module_globals[self._local_name] = module

    # Update this object's dict so that if someone keeps a reference to the
    #   LazyLoader, lookups are efficient (__getattr__ is only called on lookups
    #   that fail).
    self.__dict__.update(module.__dict__)

    return module

  def __getattr__(self, item):
    module = self._load()
    return getattr(module, item)

  def __dir__(self):
    module = self._load()
    return dir(module)

代码说明:

类 LazyLoader 继承自 types.ModuleType,初始化函数确保惰性模块将像真正的模块一样正确添加到全局变量中,只要真正用到模块的时候,也就是执行 __getattr__ 或 __dir__ 时,才会真正的 import 实际模块,更新全局变量以指向实际模块,并且将其所有状态(__dict__)更新为实际模块的状态,以便对延迟加载的引用,加载模块不需要每次访问都经过加载过程。

代码使用:

正常情况下我们这样导入模块:

import tensorflow.contrib as contrib

其对应的惰性导入版本如下:

contrib = LazyLoader('contrib', globals(), 'tensorflow.contrib')

PEP0690 建议的做法

PEP0690 的提案是在编译器( C 代码)层面实现,这样性能会更好。其使用方法有两种。

其一

一种方式是执行 Python 脚本时加入 -L 参数,比如有两个文件 spam.py 内容如下:

import time
time.sleep(10)
print("spam loaded")

egg.py 内容如下:

import spam
print("imports done")

正常导入情况下,会等 10 秒后先打印 "spam loaded",然后打印 "imports done",当执行 python -L eggs.py 时,spam 模块永远不会导入,应用 spam 模块压根就没有用到。如果 egg.py 内容如下:

import spam
print("imports done")
spam

当执行 python -L eggs.py 时会先打印 "imports done",10 秒之后打印 "spam loaded")。

其二

另一种方式是调用标准库 importlib 的方法:

import importlib 
importlib.set_lazy_imports(True)

如果某些模块不能懒加载,需要排除,可以这样

import importlib 
importlib.set_lazy_imports(True,excluding=["one.mod", "another"])

还可以这样:

from importlib import eager_imports

with eager_imports():
    import foo
    import bar

 到此这篇关于详解Python如何实现惰性导入-lazy import的文章就介绍到这了,更多相关Python惰性导入内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python中reset_index()函数的使用

    Python中reset_index()函数的使用

    本文主要介绍了Python中reset_index()函数的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • 在Tensorflow中查看权重的实现

    在Tensorflow中查看权重的实现

    今天小编就为大家分享一篇在Tensorflow中查看权重的实现,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-01-01
  • Python实现文件下载的方法汇总与适用场景介绍

    Python实现文件下载的方法汇总与适用场景介绍

    在Python开发中,文件下载是常见需求,本文将全面介绍10种Python下载文件的方法,每种方法都配有完整代码示例和适用场景分析,大家可以根据需要进行选择
    2025-05-05
  • Django如何使用redis作为缓存

    Django如何使用redis作为缓存

    这篇文章主要介绍了Django如何使用redis作为缓存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • 记一次python 爬虫爬取深圳租房信息的过程及遇到的问题

    记一次python 爬虫爬取深圳租房信息的过程及遇到的问题

    这篇文章主要介绍了记一次python 爬虫爬取深圳租房信息的过程,帮助大家更好的理解和学习python爬虫,感兴趣的朋友可以了解下
    2020-11-11
  • Python中的raise关键字详解

    Python中的raise关键字详解

    这篇文章主要介绍了Python中的raise关键字,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-04-04
  • Python模块/包安装使用入门教程

    Python模块/包安装使用入门教程

    本文介绍了Python中的模块和包的概念,包括模块的定义、导入方式、自定义模块注意事项、包的创建和使用,以及第三方包的安装和使用,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2026-02-02
  • Python通过IP地址查询地理位置的几种方法

    Python通过IP地址查询地理位置的几种方法

    本文介绍通过IP查询地理位置的两种方法:在线API(如ipinfo.io,快速但有请求限制)和本地数据库(如GeoLite2,高效但需定期更新),并推荐结合使用以满足不同场景需求,需要的朋友可以参考下
    2025-09-09
  • Python2到Python3的迁移过程中报错AttributeError: ‘str‘ object has no attribute ‘decode‘问题的解决方案大全

    Python2到Python3的迁移过程中报错AttributeError: ‘str‘ objec

    在 Python 编程过程中,AttributeError: 'str' object has no attribute 'decode' 是一个常见的错误,这通常会在处理字符串时出现,尤其是在 Python 2 到 Python 3 的迁移过程中,本文将详细介绍该问题的根源,并提供解决方案,需要的朋友可以参考下
    2025-04-04
  • Python中PyWebview库的具体使用

    Python中PyWebview库的具体使用

    pywebview是一个轻量级、跨平台的 Python 库,用于在桌面应用中嵌入系统原生的WebView组件,下面就来详细的介绍一下PyWebview库的使用,感兴趣的可以了解一下
    2025-12-12

最新评论