递归版本的“重新加载”

2024-05-14 22:41:00 发布

您现在位置:Python中文网/ 问答频道 /正文

在开发Python代码时,我通常在解释器中以特殊的方式测试它。我将import some_module,测试它,找到一个bug,修复bug并保存,然后使用内置的reload函数reload(some_module)并再次测试。

但是,假设在some_module中有import some_other_module,并且在测试some_module时,我发现some_other_module中有一个错误并修复它。现在调用reload(some_module)不会递归地重新导入some_other_module。我必须手动重新导入依赖项(通过执行类似于reload(some_module.some_other_module),或import some_other_module; reload(some_other_module)的操作),或者,如果我更改了一大堆依赖项,并且忘记了需要重新加载的内容,则需要重新启动整个解释器。

更方便的是,如果有一些recursive_reload函数,我可以做recursive_reload(some_module),让Python不仅重新加载some_module,而且递归地重新加载some_module导入的每个模块(以及每个模块导入的每个模块,所以我可以确定我没有使用some_module依赖的任何其他模块的旧版本。

我不认为Python中内置了任何类似于我在这里描述的recursive_reload函数的功能,但是有没有一种简单的方法可以将这样的东西组合在一起呢?


Tags: 模块函数代码import错误方式some手动
3条回答

我反对同一个问题,我已经建立了@Mattew和@osa的答案。

from types import ModuleType
import os, sys
def rreload(module, paths=None, mdict=None):
    """Recursively reload modules."""
    if paths is None:
        paths = ['']
    if mdict is None:
        mdict = {}
    if module not in mdict:
        # modules reloaded from this module
        mdict[module] = [] 
    reload(module)
    for attribute_name in dir(module):
        attribute = getattr(module, attribute_name)
        if type(attribute) is ModuleType:
            if attribute not in mdict[module]:
                if attribute.__name__ not in sys.builtin_module_names:
                    if os.path.dirname(attribute.__file__) in paths:
                        mdict[module].append(attribute)
                        rreload(attribute, paths, mdict)
    reload(module)
    #return mdict

有三个不同点:

  1. 在一般情况下,重载(模块)也必须在函数的末尾调用,正如@osa所指出的。
  2. 对于循环导入依赖项,前面发布的代码将永远循环,因此我添加了一个列表字典来跟踪其他模块加载的模块集。虽然循环依赖关系并不酷,但是Python允许它们,所以这个reload函数也处理它们。
  3. 我添加了允许重新加载的路径列表(默认为['')。有些模块不喜欢以正常方式重新加载(如here)。

编写一些测试用例,并在每次修改模块时运行它们,这难道不是更简单吗?

你所做的很酷(你本质上是在使用TDD(测试驱动开发),但是你做的不对。

考虑一下,通过编写单元测试(使用默认的pythonunittest模块,或者更好的是使用nose),您可以得到可重用的测试,比在交互环境中测试模块更快、更好地检测代码中的不一致性。

我遇到了同样的问题,你激励我去解决这个问题。

from types import ModuleType

try:
    from importlib import reload  # Python 3.4+
except ImportError:
    # Needed for Python 3.0-3.3; harmless in Python 2.7 where imp.reload is just an
    # alias for the builtin reload.
    from imp import reload

def rreload(module):
    """Recursively reload modules."""
    reload(module)
    for attribute_name in dir(module):
        attribute = getattr(module, attribute_name)
        if type(attribute) is ModuleType:
            rreload(attribute)

或者,如果您使用的是IPython,只需在启动时使用dreload或pass--deep-reload

相关问题 更多 >

    热门问题