【转】Python标准模块--importlib

作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明。谢谢!

1 模块简介

Python提供了importlib包作为标准库的一部分。目的就是提供Python中import语句的实现(以及__import__函数)。另外,importlib允许程序员创建他们自定义的对象,可用于引入过程(也称为importer)。

什么是imp?
另外有一个叫做imp的模块,它提供给Python import语句机制的接口。这个模块在Python 3.4中被否决,目的就是为了只使用importlib。

这个模块有些复杂,因此我们在这篇博文中主要讨论以下几个主题:

  • 动态引入
  • 检查模块是否可以被引入
  • 引入源文件自身
  • 第三方模块 import_from_github_com

2 模块使用

2.1 动态引入

importlib模块支持传入字符串来引入一个模块。我们创建两个简单的模块来验证这个功能。我们将会给予两个模块相同的接口,让它们打印名字以便我们能够区分它们。创建两个模块,分别为foo.py和bar.py,代码如下所示,

def main():
print(__name__)

现在我们使用importlib来引入它们。让我们看看这段代码如何去做的。确保你已经把这段代码放在与上面创建的两个模块相同的目录下。

#importer.py
import importlib def dynamic_import(module):
return importlib.import_module(module) if __name__ == "__main__":
module = dynamic_import('foo')
module.main() module_two = dynamic_import('bar')
module_two()

在这段代码中,我们手动引入importlib模块,并创建一个简单的函数dynamic_import。这个函数所做的就是调用importlib模块中的import_module函数,入参就是我们传入的字符串,然后返回调用结果。在代码段的下面,我们调用每个模块的main方法,将会打印出每个模块的名称。

在你的代码中,你可能不会大量这样做。当你只有一个字符串时,如果你想引入这个模块,importlib就允许你可以这么做。

2.2 模块引入检查

Python有一个编码规范就是EAPP:Easier to ask for forgiveness than permision。意思就是经常假设一些事情是存在的(例如,key在词典中),如果出错了,那么就捕获异常。你可以看 Python标准模块--import 文章中我们尝试引入模块,当它不存在时,我们就会捕获到ImportError。如果我们想检查并观察一个模块是否可以引入而不是仅仅是猜测,该如何去做?你可以使用importlib。代码如下:

#coding:utf-8

import importlib.util
import importlib def check_module(module_name):
module_spec = importlib.util.find_spec(module_name)
if module_spec is None:
print("Module :{} not found".format(module_name))
return None
else:
print("Module:{} can be imported!".format(module_name))
return module_spec def import_module_from_spec(module_spec):
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
return module if __name__ == "__main__":
module_spec = check_module("fake_module")
module_spec = check_module("collections")
if(module_spec):
module = import_module_from_spec(module_spec)
print(dir(module))

这里我们引入importlib模块的子模块util。在check_module函数中,我们调用find_spec函数来检查传入的字符串作为模块是否存在。首先,我们传入一个假的名称,然后我们传入一个Python模块的真实名称。如果你运行这段代码,你将会看到你传入一个没有安装的模块的名称,find_spec函数将会返回None,我们的代码将会打印出这个模块没有找到。如果找到了,我们就会返回模块的说明。

我们可以获取到模块的说明,然后使用它来真正的引入模块。或者你可以将字符串传入到import_module函数中,正如我们在2.1节中所学习到的一样。但是我们已经学习到如何使用模块的说明。让我们看一下上述代码中的import_module_from_spec函数。它接受由check_module函数返回的模块说明。我们将其传入到module_from_spec函数,它将会返回引入的模块。Python的官方文档推荐,在引入模块后执行它,所以我们下一步做的就是调用exec_module函数。最后我们返回这个模块,并且运行Python的dir函数来确认这个我们就是我们所期望的。

2.3 从源文件中引入

在这一节中,我想说明importlib的子模块util还有另外一个技巧。你可以使用util通过模块名和文件路径来引入一个模块。示例如下所示,

#coding:utf-8

import importlib.util

def import_source(module_name):
module_file_path = module_name.__file__
module_name = module_name.__name__ module_spec = importlib.util.spec_from_file_location(module_name,module_file_path)
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
print(dir(module)) msg = "The {module_name} module has the following methods:{methods}"
print(msg.format(module_name = module_name,methods = dir(module))) if __name__ == "__main__":
import logging
import_source(logging)

上述代码中,我们实际引入了logging模块,并将它传入到import_source函数。在这个函数中,我们首先获取到模块的实际路径和名称。然后我们将这些信息传入到util的spec_from_file_location函数中,这个将会返回模块的说明。一旦我们获取到模块的说明,我们就可以使用与2.2节相同的importlib机制来实际引入模块。

现在让我们来看一个精巧的第三方库,Python的__import__()函数直接引入github中的包。

2.4 import_from_github_com

这个精巧的包叫做import_from_github_com,它可以用于发现和下载github上的包。为了安装他,你需要做的就是按照如下命令使用pip,

pip install import_from_github_com

这个包使用了PEP 302中新的引入钩子,允许你可以从github上引入包。这个包实际做的就是安装这个包并将它添加到本地。你需要Python 3.2或者更高的版本,git和pip才能使用这个包。

一旦这些已经安装,你可以在Python shell中输入如下命令,

>>> from github_com.zzzeek import sqlalchemy
Collecting git+https://github.com/zzzeek/sqlalchemy
Cloning https://github.com/zzzeek/sqlalchemy to /tmp/pip-acfv7t06-build
Installing collected packages: SQLAlchemy
Running setup.py install for SQLAlchemy ... done
Successfully installed SQLAlchemy-1.1.0b1.dev0
>>> locals()
{'__builtins__': <module 'builtins' (built-in)>, '__spec__': None,
'__package__': None, '__doc__': None, '__name__': '__main__',
'sqlalchemy': <module 'sqlalchemy' from '/usr/local/lib/python3.5/site-packages/\
sqlalchemy/__init__.py'>,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>}

你如果看了import_from_github_com的源码,你将会注意到它并没有使用importlib。实际上,它使用了pip来安装那些没有安装的包,然后使用Python的__import__()函数来引入新安装的模块。这段代码非常值得学习。

2.5 总结

到这里,你已经了解到在你的代码中如何使用importlib和引入钩子。当然还有很多超出本文所覆盖的知识,如果你需要写一个自定义的引入器或者下载器,你需要花费很多时间来阅读官方文档和源码。

3 Reference

Python 201

【转】Python标准模块--importlib的更多相关文章

  1. Python标准模块--importlib

    作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 1 模块简介 Python提供了importlib包作为标准库的一 ...

  2. Python中标准模块importlib详解

    1 模块简介 Python提供了importlib包作为标准库的一部分.目的就是提供Python中import语句的实现(以及__import__函数).另外,importlib允许程序员创建他们自定 ...

  3. Python标准模块--threading

    1 模块简介 threading模块在Python1.5.2中首次引入,是低级thread模块的一个增强版.threading模块让线程使用起来更加容易,允许程序同一时间运行多个操作. 不过请注意,P ...

  4. Python标准模块--logging

    1 logging模块简介 logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级.日志保存路径.日志文件回滚等:相比print,具备如下优点: 可以通过设置不同 ...

  5. Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures

    参考博客: https://www.cnblogs.com/xiao987334176/p/9046028.html 线程简述 什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线 ...

  6. python 全栈开发,Day42(Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures)

    昨日内容回顾 线程什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线程是什么关系? 线程是在进程中的 一个执行单位 多进程 本质上开启的这个进程里就有一个线程 多线程 单纯的在当 ...

  7. Python标准模块--logging(转载)

    转载地址:http://www.cnblogs.com/zhbzz2007/p/5943685.html#undefined Python标准模块--logging 1 logging模块简介 log ...

  8. python全栈开发,Day42(Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures)

    昨日内容回顾 线程 什么是线程? 线程是cpu调度的最小单位 进程是资源分配的最小单位 进程和线程是什么关系? 线程是在进程中的一个执行单位 多进程 本质上开启的这个进程里就有一个线程 多线程 单纯的 ...

  9. Python标准模块--import

    1 模块简介 作为一个Python初学者,你首先要学会的知识就是如何引入其它模块或者包.但是,我发现有些开发者虽然使用Python很多年,依然不了解Python引入机制的灵活性.这篇文章,我们就会研究 ...

随机推荐

  1. 解决openoffice进程异常退出的办法

    步骤1 编写脚本 openoffice.sh #!/usr/bin/bash OPENOFFICEPID=`ps -ef|grep "/opt/openoffice4/program/sof ...

  2. ServerU FTP服务器无法上传中文名文件怎么办

    erverU是一款非常流行的FTP服务器.最新版本的默认是utf-8编码,对中文支持不够友好,容易发生无法上传本地文件名称包含中文的文件. 工具/原料   server-u 方法/步骤     进入S ...

  3. HDFS集群常见报错汇总

    HDFS集群常见报错汇总 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.DataXceiver error processing WRITE_BLOCK operation 报 ...

  4. Java lombok插件介绍

    lombok是什么? lombok是一个插件,用途是给你类里面的字段,自动的加上属性,构造器,ToString方法,Equals方法等等 lombok怎么安装? 安装网上一搜一大把,这里有一个Idea ...

  5. Netsarang

    下载 https://www.netsarang.com/zh/all-downloads/ 建议直接下载 xmanager-power-suite,里面包含了 Xmanager.Xshell.Xft ...

  6. Kafka技术内幕 读书笔记之(三) 生产者——消费者:高级API和低级API——基础知识

    1. 使用消费组实现消息队列的两种模式 分布式的消息系统Kafka支持多个生产者和多个消费者,生产者可以将消息发布到集群中不同节点的不同分区上:消费者也可以消费集群中多个节点的多个分区上的消息 . 写 ...

  7. JMX监控Hadoop的部分常用参数位置

    近期版本get无法使用,可能使用了其他参数代替,但源码中已经去掉JMX部分,也没有给出替代接口,应该是不再额外实现了. NameNode DataNode HDFS Yarn HBase MapRed ...

  8. Git(管理修改)

    现在,假定你已经完全掌握了暂存区的概念.下面,我们要讨论的就是,为什么Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件. 你会问,什么是修改?比如你新增了一行,这就是一个修改 ...

  9. Ubuntu 下使用 putty并通过 ch340 usb 串口线进行调试

    安装putty sudo apt-get install putty -y 插入usb转串口线 由于linux下没有Windos类似的设备管理器,所以我们可以通过其他方法获取对应的串口号 可以在插拔之 ...

  10. excel怎么比较两组或两列数据的相同项和不同项

    https://jingyan.baidu.com/article/c843ea0b7a2a7477921e4a47.html