Oli*_*ier 48 python import python-module ipython python-import
在使用IPython在Python中开发一个大型项目(分成几个文件和文件夹)时,我遇到了缓存导入模块的麻烦.
问题是指令import module只读取模块一次,即使该模块已经改变!因此,每次我更改包中的内容时,都必须退出并重新启动IPython.痛苦.
有没有办法正确强制重装一些模块?或者,更好的是,以某种方式阻止Python缓存它们?
我尝试了几种方法,但都没有效果.特别是我遇到了非常非常奇怪的错误,就像一些模块或变量神秘地变得相等None......
我找到的唯一明智的资源是从pyunit 重新加载Python模块,但我没有检查它.我想要那样的东西.
一个很好的替代方案是让IPython重启,或以某种方式重启Python解释器.
那么,如果你用Python开发,你找到了什么解决方案来解决这个问题?
编辑
为了清楚起见:很明显,我理解一些旧的变量取决于模块的先前状态可能会存在.那个我能接受.为什么在Python中如此难以强制重新加载模块而不会发生各种奇怪的错误?
更具体地说,如果我将整个模块放在一个文件中,module.py那么以下工作正常:
import sys
try:
del sys.modules['module']
except AttributeError:
pass
import module
obj = module.my_class()
Run Code Online (Sandbox Code Playgroud)
这段代码很漂亮,我可以在不退出IPython的情况下开发数月.
但是,每当我的模块由多个子模块组成时,地狱就会松动:
import os
for mod in ['module.submod1', 'module.submod2']:
try:
del sys.module[mod]
except AttributeError:
pass
# sometimes this works, sometimes not. WHY?
Run Code Online (Sandbox Code Playgroud)
为什么我的模块在一个大文件或几个子模块中是如此不同?为什么这种方法不起作用?
Mat*_*son 24
import检查模块是否在sys.modules,如果是,则返回它.如果要导入从磁盘加载模块,则可以先删除相应的密钥sys.modules.
有一个reload内置函数,给定一个模块对象,它将从磁盘重新加载,并将被放入sys.modules.编辑 - 实际上,它将从磁盘上的文件重新编译代码,然后在现有模块中重新评估它__dict__.可能与制作新模块对象有很大不同.
迈克格雷厄姆是对的; 如果您甚至有一些活动对象引用您不再需要的模块内容,那么重新加载就很难了.现有对象仍将引用它们实例化的类是一个明显的问题,但是通过方法创建的所有引用from module import symbol仍将指向旧版本模块中的任何对象.许多巧妙的错误都是可能的.
编辑:我同意重新启动解释器的共识是迄今为止最可靠的事情.但出于调试目的,我想你可以尝试类似下面的内容.我确定有一些不适用的极端情况,但是如果你没有做任何过于疯狂的事情(否则)你的软件包加载模块,它可能会有用.
def reload_package(root_module):
package_name = root_module.__name__
# get a reference to each loaded module
loaded_package_modules = dict([
(key, value) for key, value in sys.modules.items()
if key.startswith(package_name) and isinstance(value, types.ModuleType)])
# delete references to these loaded modules from sys.modules
for key in loaded_package_modules:
del sys.modules[key]
# load each of the modules again;
# make old modules share state with new modules
for key in loaded_package_modules:
print 'loading %s' % key
newmodule = __import__(key)
oldmodule = loaded_package_modules[key]
oldmodule.__dict__.clear()
oldmodule.__dict__.update(newmodule.__dict__)
Run Code Online (Sandbox Code Playgroud)
我非常简单地测试过这样:
import email, email.mime, email.mime.application
reload_package(email)
Run Code Online (Sandbox Code Playgroud)
打印:
reloading email.iterators
reloading email.mime
reloading email.quoprimime
reloading email.encoders
reloading email.errors
reloading email
reloading email.charset
reloading email.mime.application
reloading email._parseaddr
reloading email.utils
reloading email.mime.base
reloading email.message
reloading email.mime.nonmultipart
reloading email.base64mime
Run Code Online (Sandbox Code Playgroud)
Mik*_*ham 12
退出并重新启动解释器是最佳解决方案.任何类型的实时重新加载或不缓存策略都无法无缝地工作,因为来自不再存在的模块的对象可能存在,并且因为模块有时会存储状态,并且因为即使您的用例确实允许热重新加载它也太复杂而无法考虑值得.
ojd*_*jdo 11
使用IPython时,自动重载扩展会在每次函数调用之前自动重复导入.它至少在简单的情况下起作用,但不要过分依赖它:根据我的经验,仍然需要不时地重新启动解释器,特别是当代码更改仅在间接导入的代码上发生时.
链接页面的用法示例:
In [1]: %load_ext autoreload
In [2]: %autoreload 2
In [3]: from foo import some_function
In [4]: some_function()
Out[4]: 42
In [5]: # open foo.py in an editor and change some_function to return 43
In [6]: some_function()
Out[6]: 43
Run Code Online (Sandbox Code Playgroud)
import importlib
importlib.reload(<package_name>)
from <package_name> import <method_name>
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅以下文档。
这里已经有一些非常好的答案,但值得了解 dreload,它是 IPython 中可用的一个函数,可以作为“深度重新加载”。从文档:
IPython.lib.deepreload 模块允许您递归地重新加载模块:对其任何依赖项所做的更改都将重新加载而无需退出。要开始使用它,请执行以下操作:
http://ipython.org/ipython-doc/dev/interactive/reference.html#dreload
它在 IPython notebook(至少我的版本,运行 v2.0)中作为“全局”可用。
HTH