重新加载本地模块不起作用

Jam*_*ght 1 python ipython python-3.x python-importlib

首先,我知道这之前已经发布过,但是要么 A)建议不起作用,要么 B)建议从命名空间中手动删除模块并像平常一样重新导入它。

我有以下模块结构

basedir/
    pytools/
        __init__.py
        tools.py
    setup.py
    test.py
Run Code Online (Sandbox Code Playgroud)

如果我在basedir,并导入pytools并创建一个 类 的对象testcls。该类的实际属性可在 中找到tools.pytestcls有一个名为的方法,它现在testfunc就简单地打印出来:AAA

>>> import pytools
>>> test = pytools.testcls()
>>> test.testfunc()
AAA
Run Code Online (Sandbox Code Playgroud)

假设我更改testfunc()为现在打印出来BBB。我这样做,并保存文件。然后我重新加载模块并重试,它没有打印出来BBB

>>> from importlib import reload
>>> reload(pytools)
>>> test = pytools.testcls()
>>> test.testfunc()
AAA
Run Code Online (Sandbox Code Playgroud)

但是,如果我执行完全相同的过程,但改为更改test.py,将该文件作为模块导入,编辑其中的函数,然后重新加载它,它的行为将按预期进行:

>>> import test
>>> testvariable = test.testcls()
>>> testvariable.testfunc2()
AAA
# Change the function here
>>> from importlib import reload
>>> reload(test)
>>> testvariable = test.testcls()
>>> testvariable.testfunc2()
BBB
Run Code Online (Sandbox Code Playgroud)

我真的不明白发生了什么事,这让我很恼火。这也花费了我很多时间,但我现在更恼火。

有什么想法吗?

版本:

蟒蛇:3.6.5

解释器:IPython,6.2.1

jed*_*rds 5

让我们更笼统地命名一些东西:

\n\n
basedir/\n    testpackage/\n        __init__.py\n        testmodule.py\n    test.py\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果 testmodule.py 包含:

\n\n
class TestClass:\n    def test_method(self):\n        print("AAA")\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后,以下内容将按您的预期工作:

\n\n
>>> from testpackage import testmodule\n>>> obj = testmodule.TestClass()\n>>> obj.test_method()\nDDD\n>>> # === Edit ===\n>>> from importlib import reload\n>>> reload(testmodule)\n>>> obj = testmodule.TestClass()\n>>> obj.test_method()\nEEE\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是,如果__init__.py有类似的东西:

\n\n
from .testmodule import TestClass\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后您尝试导入(并重新加载)而不是模块时,会发生以下情况:

\n\n
>>> import testpackage\n>>> obj = testpackage.TestClass()\n>>> obj.test_method()\nEEE\n>>> # === Edit ===\n>>> from importlib import reload\n>>> reload(testpackage)\n>>> obj = testpackage.TestClass()\n>>> obj.test_method()\nEEE\n
Run Code Online (Sandbox Code Playgroud)\n\n

(不变)

\n\n

请注意文档的以下部分:

\n\n
\n

如果一个模块使用 from \xe2\x80\xa6 import \xe2\x80\xa6 从另一个模块导入对象,则为另一个模块调用 reload() 不会重新定义从 \xe2\x80\x94 导入的对象一种是重新执行from语句,另一种是使用import和限定名(module.name)代替。

\n
\n\n

如果您要按顺序重新加载模块和包,它会再次按您的预期工作:

\n\n
>>> import testpackage\n>>> obj = testpackage.TestClass()\n>>> obj.test_method()\nHHH\n>>> # === Edit ===\n>>> from importlib import reload\n>>> reload(testpackage.testmodule)\n>>> reload(testpackage)\n>>> obj = testpackage.TestClass()\n>>> obj.test_method()\nIII\n
Run Code Online (Sandbox Code Playgroud)\n\n

但这看起来很愚蠢而且容易出错,只需使用第一个示例中的方法即可:

\n\n
from testpackage import testmodule\n...\nreload(testmodule)\n... \n
Run Code Online (Sandbox Code Playgroud)\n