如何在Python shell中重新加载类?
如果我导入一个模块,而这个模块里有一个和它同名的类,并且这个模块属于一个包,那么它会被当作类导入,而不是模块。这是因为父包里的 __init__.py 文件的原因。想了解更多细节,可以查看这个链接:不同目录下的导入结果。
在 Python 终端或者 ipython 终端里,如果我输入
from MyPak import MyMod
那么 MyModule 总是会被当作类导入,所以我不能重新加载它(reload() 只对模块有效)。再次运行
from MyPak import MyMod
似乎也不会更新这个类的定义。有没有人能建议我在 Python 终端里怎么更新这个类呢?
附注:不想重启 Python 解释器。
附附注:如果你手头有代码想测试一下:我其实是在说 BioPython,我正在处理 Bio.PDB.PDBParser。我有一个 ipython 终端(版本 0.10),并且在编辑 PDBParser.py。就是没有办法在 ipython 里重新加载它。
所以我做了以下操作:
# start ipython v0.10
import Bio
from Bio.PDB import PDBParser
p = PDBParser()
s = p.get_structure()
# then I make changes,e.g. simply print some text, in PDBParser.py
del Bio
del PDBParser
del s
import Bio # or reload(Bio) without deleting all the objects
from Bio.PDB import PDBParser
p = PDBParser()
s = p.get_structure() # expected output after change not seen :(
但是我没有看到打印的文本。更改似乎没有生效。
7 个回答
有三种方法可以解决这个问题:
1. 使用 import MyPak.MyMod
而不是 from MyPak import MyMod
这样你就可以写:
from importlib import reload # If on Python 3
import MyPak.MyMod
reload(MyPak.MyMod)
然后它就能正常工作了。
2. 使用 IPython.lib.deepreload
from MyPak import MyMod
from IPython.lib.deepreload import reload
reload(MyPak) # This should also reload all submodules
3. 使用 autoreload 魔法
%load_ext autoreload
%autoreload 2
import MyPak.MyMod # All changes to MyPak.MyMod will be loaded automatically
在Python 3中,首先要导入reload
这个函数:
>>> from importlib import reload
在Python 2.x和3.x中,你可以直接对模块调用reload
:
>>> import MyPak
>>> reload(MyPak)
>>> from MyPak import MyMod
不过,旧类的实例不会被更新(因为没有代码来描述更新的机制)。
我终于找到了答案:
import MyPak
from MyPak import MyMod
在编辑了 MyPak/MyMod.py
文件后,要重新加载这个文件里的 MyMod
类,需要做以下操作:
import sys
del sys.modules['MyPak.MyMod']
reload(MyPak)
from MyPak import MyMod
注意事项:
执行
del MyPak
、del MyMod
或del MyPak.MyMod
并不能解决问题,因为这只是删除了名字的绑定。Python 只会查看sys.modules
来判断模块是否已经被导入。可以参考这个帖子中的讨论:sys.modules 和 globals() 中的模块名。当重新加载 MyPak 时,Python 会尝试执行
from MyMod import MyMod
这一行代码,这行代码在MyPak/__init__.py
文件中。然而,它在sys.modules
中找到了MyPak.MyMod
,因此它不会重新加载MyMod
,即使MyPak/MyMod.py
已经更新了。你会发现没有生成新的MyPak/MyMod.pyc
文件。