python动态导入模块并reload类及函数

我又来分享开源模块了,项目名是pyautoreload,这是前段时间写后端服务时用到的模块,我现在独立插取成一个项目,开源出来,希望这模块对大家有些用处…


关于python各种方法导入模块的介绍,如何reload重新加载类及函数原文地址是:

http://xiaorui.cc  http://xiaorui.cc/?p=2065


pyautoreload这名字,一看就知道是干嘛的? 对的,他确实是个动态导入模块,并重新加载的模块的模块,有点绕口…

一说载入模块,大家肯定会首先想到的是平时常用的import xx , from xiaorui.cc import view 这样的用法,但是这种用法适合咱们python程序一开始加载,绝大数的场景都是一开头就加载需要的模块.

首先我们做个测试:

filename: a.py  

#encoding: utf-8  
import os  
print 'in a.py',id(os)  
  
filename: m.py  

#encoding: utf-8  
import a   #第一次会打印a里面的语句  
import os  #再次导入os后,其内存地址和a里面的是一样的,因此这里只是对os的本地引用  
print 'in m.py',id(os)  
import a  #第二次不会打印a里面的语句,因为已经加载过了


我这里会用到__import__,他的功能跟importlib是一样的。 都可以把字符串形式的模块导入到python环境里面。虽然跟同import语句同样的功能,但__import__和importlib是函数,并且只接收字符串作为参数,所以它的作用你也就懂了,比如celery rq这样的工作任务队列,就会有这种动态加载模块的需求….

看了下python文档,发现import语句底层也是__import__ 


__import__的详细用法.
__import__(module_name[, globals[, locals[, fromlist]]]) #可选参数默认为globals(),locals(),[] 从globals locals里面寻找fromlist里面的函数.
__import__(‘os’)    
__import__(‘os’,globals(),locals(),[‘xiaorui’,’fengyun’])  #等价于from os import xiaorui,fengyun

通常在动态加载时可以使用到这个函数,比如你希望加载某个文件夹下的所用模块,但是其下的模块名称又会经常变化时,就可以使用这个函数动态加载所有模块了,最常见的场景就是插件功能的支持。
扩展:
既然可以通过字符串来动态导入模块,那么是否可以通过字符串动态重新加载模块吗?试试reload(‘os’)直接报错。

In [145]: reload(‘os’)
—————————————————————————
TypeError                                 Traceback (most recent call last)
<ipython-input-145-e7052c614626> in <module>()
—-> 1 reload(‘os’)

TypeError: reload() argument must be module

记住 !不能直接reload一个字符串,但是可以有两种方法来解决你的需求。

第一种可以先unimport你指定的模块,然后再__import__、importlib重新加载模块。在python解释里可以通过globals(),locals(),vars(),dir()等函数查看到当前环境下加载的模块及其位置,除此之外sys.modules,通过sys.modules可以查看所有的已加载并且成功的模块。那么怎么让模块改成unimport状态? 直接删除….

#encoding: utf-8  
import sys  
__import__('a')      
del sys.modules['a']   #unimport  
__import__('a')   
__import__('a')

第二种方法,比较优雅点… 其实方法的根据都是通过sys.modules来查找他的模块对象。另外模块的重新加载也不只是有reload这个函数,imp也有reload函数。暂时没发现啥区别。

reload(sys.modules['a'])

一个小技巧:

locals() globals()可以看到详细的当前所有的对象。如果想看具体有啥,可以用dir(mq), vars(mq)更详细看到对象内置的信息。如果想实现所有模块重载,其实可以直接把globals里面对象,判断取出type为module的,然后加载一遍就行了。

 ‘buzz.lib.mq’: <module ‘buzz.lib.mq’ from ‘buzz/lib/mq.pyc’>,
 ‘buzz.lib.msgpack’: None,
 ‘buzz.lib.os’: None,
 ‘buzz.lib.pwd’: None,
 ‘buzz.lib.re’: None,
 ‘buzz.lib.redis’: None,
 ‘buzz.lib.serialize’: <module ‘buzz.lib.serialize’ from ‘buzz/lib/serialize.pyc’>,
 ‘buzz.lib.singleton’: <module ‘buzz.lib.singleton’ from ‘buzz/lib/singleton.pyc’>,

pyhton的解释器里面往往包含了一些内建函数,如果我们想重载所有模块的时候,可以首先去除内建函数。  imp.is_builtin() \  sys.builtin_module_names()

好了,开始介绍前几天提交的简约版的pyautoreload项目。 现在功能主要是模块导入及reload,过几天我会加入watch机制和信号机制。 


项目名:  pyautoreload

github:   https://github.com/rfyiamcool/pyautoreload

PYPI:     https://pypi.python.org/pypi/pyautoreload 


安装方法:

pypi安装

pip install pyautoreload

源码安装

git clone https://github.com/rfyiamcool/pyautoreload.git
cd pyautoreload
python setup.py install

使用方法:

重新加载指定模块

pyautoreload.reload_module(m)

加入模块

pyautoreload.import_str(‘a.b.c.d’)

路径: /a/b/c

函数: d

删除模块

delete_str(m)

重新加载所有模块

reload_all()

重新加载模块,支持类及函数路径模式

reload_str()


大家觉得文章对你有些作用! 如果想赏钱,可以用微信扫描下面的二维码,感谢!
另外再次标注博客原地址  xiaorui.cc

1 Response

  1. 亲亲啊宝贝 2015年10月7日 / 下午8:41

    世界上唯一不变的,就是一切都在变。

发表评论

邮箱地址不会被公开。 必填项已用*标注