如何在Python shell中重新加载类?

84 投票
7 回答
94519 浏览
提问于 2025-04-16 22:54

如果我导入一个模块,而这个模块里有一个和它同名的类,并且这个模块属于一个包,那么它会被当作类导入,而不是模块。这是因为父包里的 __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 个回答

24

有三种方法可以解决这个问题:

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
105

在Python 3中,首先要导入reload这个函数:

>>> from importlib import reload

在Python 2.x和3.x中,你可以直接对模块调用reload

>>> import MyPak
>>> reload(MyPak)
>>> from MyPak import MyMod

不过,旧类的实例不会被更新(因为没有代码来描述更新的机制)。

48

我终于找到了答案:

import MyPak
from MyPak import MyMod

在编辑了 MyPak/MyMod.py 文件后,要重新加载这个文件里的 MyMod 类,需要做以下操作:

import sys
del sys.modules['MyPak.MyMod'] 
reload(MyPak)
from MyPak import MyMod

注意事项

  1. 执行 del MyPakdel MyModdel MyPak.MyMod 并不能解决问题,因为这只是删除了名字的绑定。Python 只会查看 sys.modules 来判断模块是否已经被导入。可以参考这个帖子中的讨论:sys.modules 和 globals() 中的模块名

  2. 当重新加载 MyPak 时,Python 会尝试执行 from MyMod import MyMod 这一行代码,这行代码在 MyPak/__init__.py 文件中。然而,它在 sys.modules 中找到了 MyPak.MyMod,因此它不会重新加载 MyMod,即使 MyPak/MyMod.py 已经更新了。你会发现没有生成新的 MyPak/MyMod.pyc 文件。

撰写回答