详解Python如何实现惰性导入-lazy import
作者:somenzz 发布时间:2023-12-22 20:15:43
前言
如果你的 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
来源:https://mp.weixin.qq.com/s/KPt7Hs7_qIHxvG8drub3Gg
猜你喜欢
- DateDiff(timeinterval,date1,date2 [, firstdayofweek [, firstweekofyear
- 示例from optparse import OptionParser[...]def main():
- 有时候会碰到需求,将字典来反转,即:字典中的键作为值,而字典中的值作为键。对于字典比较小,可以使用普通方法方法一:使用普通方法转换>&
- 终于开始做用户部分了,先做注册一用户 1.1用户注册 首先在Models里添加用户注册模型类UserRegister 继
- 一、安装mongo plugs插件File->SettingPlugins查询Mongo选择Search in repositorie
- Jquery中的一些东西学习一下子,补充完善一下,毕竟有些时候没有使用到这个方式很有用,在使用bootstrap table的时候,选择当前
- 在注册或购物车结帐的时候,需要用户填入个人资料,这个环节可以简练一下,我们只需客人填入邮政编码,然后就根据这个邮政编码,自动从数据库中取出相
- 我来讲解属性部分, 这是相当有用的, 可要认真上课.首先,jquery中对html标签属性进行操作的关键词是 attr .没错,就4个字母,
- 在使用django-rest-framework开发项目的时候我们总是避免不了跨域的问题,因为现在大多数的项目都是前后端分离,前后端项目部署
- 开源监控系统 Prometheus 集成了跟踪多种类型的时间序列数据,但如果没有集成你想要的数据,那么很容易构建一个。一个经常使用的例子使用
- 下载依赖首先需要下载hadoop和spark,解压,然后设置环境变量。hadoop清华源下载spark清华源下载HADOOP_HOME =&
- 一、桥接模式桥接模式,希望能够将一个事物的两个维度分离(解耦),使其都可以独立地变化,并通过桥梁连接起来。(类)抽象部分(Abstracti
- 本文实例讲述了python集合的创建、添加及删除操作。分享给大家供大家参考,具体如下:集合时无序可变的序列,集合中的元素放在{}内,集合中的
- python 获取网页编码方式实现代码<span style="font-family: Arial, Helvetica,
- 用来批量切割视频的开头部分,比如去掉一部电视剧的序幕,看着难受不说数量还很多,很菜鸟的一篇,毕竟我也是一个菜鸟,首先要有ffmpeg这个软件
- 本文实例讲述了Python编程实现的简单神经网络算法。分享给大家供大家参考,具体如下:python实现二层神经网络包括输入层和输出层# -*
- 九宫格是一种比较古老的设计,它最基本的表现其实就像是一个三行三列的表格。其实它最初是在window的c/s结构中用得比较多,比如我们经常看到
- 如要让数据库进行自动管理,则管理员需要预先定义一些可预测的管理任务以及这些任务发送的条件。当满足这些指定的条件,则数据库会自动运行管理员指定
- 用python加“验证码”为关键词在baidu里搜一下,可以找到很多关于验证码识别的文章。我大体看了一下,主要方法有几类:一类是通过对图片进
- 大家好,我是辰哥~今天给大家分享两个制作二维码的Python库,可以生成普通的二维码、图片背景版二维码、动图GIF版二维。1.MyQR安装p