代码之家  ›  专栏  ›  技术社区  ›  funklute

如何强制ipython深度重新加载?

  •  6
  • funklute  · 技术社区  · 7 年前

    我正在通过run magic在ipython中运行一个脚本:

    %run myscript.py
    

    这个脚本导入了我编写的各种模块,我经常在运行之间更改这些模块。我想自动重新加载这些模块,而不必重新启动ipython。关于stackoverflow和其他建议

    %load_ext autoreload
    %autoreload 2
    

    也许还有

     %aimport <your module>
    

    为了更好的衡量而投入。但这根本不起作用。深度重新加载是否超出了autoreload的能力?是否有其他方法可以删除所有加载的模块,或者以静默方式重新启动ipython所依赖的python后台进程?

    编辑:在对这一点进行了更多的研究之后,autoreload失败似乎更为微妙。可能(我还不能百分之百确定)只有在我的模块的\uu init\uuuuuuuuu时自动加载才会失败。py正在做 from .<some file in the module> import * ,而不是按名称导入每个成员。我也试过 %reset 魔法,但这只会清空名称空间,不会清除缓存的模块。

    顺便说一句,Spyder能够强制重新加载模块,但我不确定这是如何做到的(某种围绕ipython的包装,它可以重新启动进程?)

    1 回复  |  直到 7 年前
        1
  •  7
  •   funklute    7 年前

    我查了Spyder的解决方案,它基本上使用 del 在…上 sys.modules 。下面我稍微修改了在中找到的代码 ~/anaconda3/lib/python3.6/site-packages/spyder/utils/site/sitecustomize.py ,我把它放在一个叫做 reloader.py :

    import sys
    
    
    def _is_module_deletable(modname, modpath):
        if modname.startswith('_cython_inline'):
            # Don't return cached inline compiled .PYX files
            return False
        for path in [sys.prefix]:
            if modpath.startswith(path):
                return False
        else:
            return set(modname.split('.'))
    
    
    def clear():
        """
        Del user modules to force Python to deeply reload them
    
        Do not del modules which are considered as system modules, i.e.
        modules installed in subdirectories of Python interpreter's binary
        Do not del C modules
        """
        log = []
        for modname, module in list(sys.modules.items()):
            modpath = getattr(module, '__file__', None)
    
            if modpath is None:
                # *module* is a C module that is statically linked into the
                # interpreter. There is no way to know its path, so we
                # choose to ignore it.
                continue
    
            if modname == 'reloader':
                # skip this module
                continue
    
            modules_to_delete = _is_module_deletable(modname, modpath)
            if modules_to_delete:
                log.append(modname)
                del sys.modules[modname]
    
        print("Reloaded modules:\n\n%s" % ", ".join(log))
    

    现在就做吧 import reloader 然后打电话 reloader.clear()