Python中标准模块importlib详解

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和引入钩子。当然还有很多超出本文所覆盖的知识,如果你需要写一个自定义的引入器或者下载器,你需要花费很多时间来阅读官方文档和源码。

(0)

相关推荐

  • Python urllib模块urlopen()与urlretrieve()详解

    1.urlopen()方法urllib.urlopen(url[, data[, proxies]]) :创建一个表示远程url的类文件对象,然后像本地文件一样操作这个类文件对象来获取远程数据.参数url表示远程数据的路径,一般是网址:参数data表示以post方式提交到url的数据(玩过web的人应该知道提交数据的两种方式:post与get.如果你不清楚,也不必太在意,一般情况下很少用到这个参数):参数proxies用于设置代理.urlopen返回 一个类文件对象,它提供了如下方法:read(

  • python中使用smtplib和email模块发送邮件实例

    SMTP模块 这么多已定义的类中,我们最常用的的还是smtplib.SMTP类,就具体看看该类的用法:smtp实例封装一个smtp连接,它支持所有的SMTP和ESMTP操作指令,如果host和port参数被定义,则smtp会在初始化期间自动调用connect()方法,如果connect()方法失败,则会触发SMTPConnectError异常,timeout参数设置了超时时间.在一般的调用过程中,应该遵connetc().sendmail().quit()步骤. SMTP模块主要方法 下面我们来

  • python中urllib模块用法实例详解

    本文实例讲述了python中urllib模块用法.分享给大家供大家参考.具体分析如下: 一.问题: 近期公司项目的需求是根据客户提供的api,我们定时去获取数据, 之前的方案是用php收集任务存入到redis队列,然后在linux下做一个常驻进程跑某一个php文件, 该php文件就一个无限循环,判断redis队列,有就执行,没有就break. 二.解决方法: 最近刚好学了一下python, python的urllib模块或许比php的curl更快,而且简单. 贴一下代码 复制代码 代码如下: #

  • Python使用urllib模块的urlopen超时问题解决方法

    在新的公司开始上班,今天工作的主题内容是市场部门需要抓取一些论坛用户的邮箱,以便发送营销邮件. 于是用了一个python脚本来执行,前面抓了几个都没有什么问题,后来碰到一个论坛,在执行urlopen的地方总是提示超时,百度了一下,因为我使用的是urllib不是urllib2,所以无法直接在urlopen里面加timeout参数,只能是设置全局脚本的超时时间 首先: 复制代码 代码如下: import socket 然后: 复制代码 代码如下: socket.setdefaulttimeout(6

  • 从零学python系列之新版本导入httplib模块报ImportError解决方案

    之前用Python 2.7版本的httplib做接口测试时,运行代码都是正常的, 最近开始用Python 3.3之后,再去看以前的代码,发现import httplib出现错误:Unresolved import :httplib, 运行代码时也报错:ImportError: No module named 'httplib' 查找各种资料发现原来Python 2.x中的"httplib"模块在Python 3.x中变成了"http.client",就怪之前只了解了

  • Python中的Matplotlib模块入门教程

    1 关于 Matplotlib 模块 Matplotlib 是一个由 John Hunter 等开发的,用以绘制二维图形的 Python 模块.它利用了 Python 下的数值计算模块 Numeric 及 Numarray,克隆了许多 Matlab 中的函数, 用以帮助用户轻松地获得高质量的二维图形.Matplotlib 可以绘制多种形式的图形包括普通的线图,直方图,饼图,散点图以及误差线图等:可以比较方便的定制图形的各种属性比如图线的类型,颜色,粗细,字体的大小等:它能够很好地支持一部分 Te

  • Python中标准模块importlib详解

    1 模块简介 Python提供了importlib包作为标准库的一部分.目的就是提供Python中import语句的实现(以及__import__函数).另外,importlib允许程序员创建他们自定义的对象,可用于引入过程(也称为importer). 什么是imp? 另外有一个叫做imp的模块,它提供给Python import语句机制的接口.这个模块在Python 3.4中被否决,目的就是为了只使用importlib. 这个模块有些复杂,因此我们在这篇博文中主要讨论以下几个主题: •动态引入

  • Python中Numpy模块使用详解

    目录 NumPy ndarray对象 ​ ​Numpy数据类型​​ Numpy数组属性 NumPy NumPy(Numerical Python) 是 Python 的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库.Nupmy可用来存储和处理大型矩阵,比Python自身的嵌套列表(nested list structure)结构要高效的多(该结构也可以用来表示矩阵(matrix)).据说NumPy将Python相当于变成一种免费的更强大的MatLab系统.

  • Python中itertools模块用法详解

    本文实例讲述了Python中itertools模块用法,分享给大家供大家参考.具体分析如下: 一般来说,itertools模块包含创建有效迭代器的函数,可以用各种方式对数据进行循环操作,此模块中的所有函数返回的迭代器都可以与for循环语句以及其他包含迭代器(如生成器和生成器表达式)的函数联合使用. chain(iter1, iter2, ..., iterN): 给出一组迭代器(iter1, iter2, ..., iterN),此函数创建一个新迭代器来将所有的迭代器链接起来,返回的迭代器从it

  • python中 logging的使用详解

    日志是用来记录程序在运行过程中发生的状况,在程序开发过程中添加日志模块能够帮助我们了解程序运行过程中发生了哪些事件,这些事件也有轻重之分. 根据事件的轻重可分为以下几个级别: DEBUG: 详细信息,通常仅在诊断问题时才受到关注.整数level=10 INFO: 确认程序按预期工作.整数level=20 WARNING:出现了异常,但是不影响正常工作.整数level=30 ERROR:由于某些原因,程序 不能执行某些功能.整数level=40 CRITICAL:严重的错误,导致程序不能运行.整数

  • python logging日志模块的详解

    python logging日志模块的详解 日志级别 日志一共分成5个等级,从低到高分别是:DEBUG INFO WARNING ERROR CRITICAL. DEBUG:详细的信息,通常只出现在诊断问题上 INFO:确认一切按预期运行 WARNING:一个迹象表明,一些意想不到的事情发生了,或表明一些问题在不久的将来(例如.磁盘空间低").这个软件还能按预期工作. ERROR:更严重的问题,软件没能执行一些功能 CRITICAL:一个严重的错误,这表明程序本身可能无法继续运行 这5个等级,也

  • Python中itertools的用法详解

    iterator 循环器(iterator)是对象的容器,包含有多个对象.通过调用循环器的next()方法 (next()方法,在Python 3.x中),循环器将依次返回一个对象.直到所有的对象遍历穷尽,循环器将举出StopIteration错误. 在for i in iterator结构中,循环器每次返回的对象将赋予给i,直到循环结束.使用iter()内置函数,我们可以将诸如表.字典等容器变为循环器.比如 for i in iter([2, 4, 5, 6]): print i 标准库中的i

  • python中time包实例详解

    在python中基础的时间运用,离不开time函数的支持.这些函数为了方便调用集中放在一个地方,叫做time包.有的人会仔细追寻time包的来源,会发现它和C语言有密不可分的关系.下面我们简单介绍time包的概念,然后就包中的一些函数进行列举,并附上对应的使用方法. 1.概念 time包基于C语言的库函数(library functions).Python的解释器通常是用C编写的,Python的一些函数也会直接调用C语言的库函数. 2.time包中的函数 time.clock()返回程序运行的整

  • Python之re模块案例详解

    一.正则表达式   re模块是python独有的匹配字符串的模块,该模块中提供的很多功能是基于正则表达式实现的,而正则表达式是对字符串进行模糊匹配,提取自己需要的字符串部分,他对所有的语言都通用.注意: re模块是python独有的 正则表达式所有编程语言都可以使用 re模块.正则表达式是对字符串进行操作 因为,re模块中的方法大都借助于正则表达式,故先学习正则表达式. (一)常用正则  1.字符组 在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示 正则 待匹配字符 匹配

  • python中异常的传播详解

    目录 1.异常的传播 2.如何处理异常 1.异常的传播 当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播.如果函数中没有对异常进行处理,则异常会继续向函数调用者传播.如果函数调用者处理了异常,则不再传播,如果还没有处理,则继续向他的调用者传播,直到传递到全局作用域(主模块)如果依然没有处理,则程序终止,并且显示异常信息到控制台.所以异常的传播我们也称之为抛出异常. 异常传播示例如下: def fn1(): print('Hello fn') print(10/0) def

  • Python中的flask框架详解

    Flask是一个Python编写的Web 微框架,让我们可以使用Python语言快速实现一个网站或Web服务.本文参考自Flask官方文档,大部分代码引用自官方文档. 安装flask 首先我们来安装Flask.最简单的办法就是使用pip. pip install flask 然后打开一个Python文件,输入下面的内容并运行该文件.然后访问localhost:5000,我们应当可以看到浏览器上输出了hello world. from flask import Flask app = Flask(

随机推荐