详解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


猜你喜欢
- 先谈一下面包屑的由来:很久很久以前,在大森林的边上住着一个贫穷的樵夫,他妻子和两个孩子与他相依为命。他的儿子名叫汉赛尔,女儿名叫格莱特。后来
- 本人最近在学习python,在看了一些教程后,用python写了一个简单的云音乐播放器,下面把主要代码贴上来,其中用到了github上他人写
- 在python中,它也有这个含义,不过有点区别的是,“当...时候”这个条件成立在一段范围或者时间间隔内,从而在这段时间间隔内让python
- python判断图片主色调,单个颜色:#!/usr/bin/env python# -*- coding: utf-8 -*-import
- 因为需要一个html形式的数据统计界面,所以做了一个基于pyecharts包的可视化程序,当然matplotlib还是常用的数据可视化包,只
- 一.克隆表法一mysql> create table info1 like info;复制格式,通过LIKE方法,复制info表结构生
- 1.创建应用django-admin startproject cloudmscd cloudmspython manage.py star
- 本文主要介绍了用OpenCV进行年龄和性别检测的实现示例,分享给大家,具体如下:在本文中,我将带您完成用 Python 进行机器学习的年龄和
- Python——re模块 简介定义:re模块称为正则表达式;作用:创建一个"规则表达式",用于验证和查找符合规
- 实例如下所示:#!/usr/bin/python# -*- coding: UTF-8 -*-import reimport urllib,
- 今晚读了think in java 的章节,感觉很不错,我就敲了下来,贴上代码给以后一个回顾: 建议提前读一下think in j
- 背景说的事务,大家应该都不陌生,开发用到 MySql 数据库的时候,通常会用到事务。其中比较经典的例子就是转账,比如你要给小明转 50 块钱
- Python引入了一个机制:引用计数。引用计数python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,
- 本文为大家分享了数据库优化方案,供大家参考,具体内容如下1. 利用表分区分区将数据在物理上分隔开,不同分区的数据可以制定保存在处于不同磁盘上
- 1. 为什么需要Simhash?传统相似度算法:文本相似度的计算,一般使用向量空间模型(VSM),先对文本分词,提取特征,根据特征建立文本向
- 代码如下:using System; using System.Data; using System.Configuration
- 可以去官网下载,我百度网盘也有都一样链接: https://pan.baidu.com/s/1fhEJu_9Zas364bvlEimRLA
- 我的数据库如图结构我取了其中的name age nr,做成array,只要所取数据存在str型,那么取出的数据,全部转化为str型,也就是a
- 如下所示:daffodil = int(input('请输入一个三位数:'))if daffodil == pow(daff
- 最近在使用Go语言搞一个用户登录&注册的功能,说到登录&注册相关,我们油然会产生一种增加验证码的想法,因此着手实现,后来在G