Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 递归版本的';重新加载';_Python_Python Module_Python Import - Fatal编程技术网

Python 递归版本的';重新加载';

Python 递归版本的';重新加载';,python,python-module,python-import,Python,Python Module,Python Import,当我开发Python代码时,我通常在解释器中以一种特殊的方式进行测试。我将导入一些模块,测试它,找到一个bug,修复bug并保存,然后使用内置的重新加载功能来重新加载(一些模块),然后再次测试 但是,假设在某个模块中,我导入了一些其他模块,并且在测试某个模块时,我在某个其他模块中发现了一个bug并修复了它。现在调用reload(some\u模块)将不会递归地重新导入some\u other\u模块。我必须手动重新导入依赖项(通过执行类似于reload(some\u module.some\u o

当我开发Python代码时,我通常在解释器中以一种特殊的方式进行测试。我将
导入一些模块
,测试它,找到一个bug,修复bug并保存,然后使用内置的
重新加载
功能来
重新加载(一些模块)
,然后再次测试

但是,假设在
某个模块
中,我导入了一些其他模块,并且在测试
某个模块
时,我在
某个其他模块
中发现了一个bug并修复了它。现在调用
reload(some\u模块)
将不会递归地重新导入
some\u other\u模块
。我必须手动重新导入依赖项(通过执行类似于
reload(some\u module.some\u other\u module)
的操作,或者
导入some\u other\u module;reload(some\u other\u module)
,或者,如果我更改了一大堆依赖项并失去了需要重新加载的内容,我需要重新启动整个解释器

更方便的是如果有一些
recursive\u reload
函数,我可以做
recursive\u reload(some\u module)
,让Python不仅重新加载
some\u module
,而且递归地重新加载
some\u module
导入的每个模块(以及每个模块导入的每个模块,等等),这样我就可以确保我没有使用某个模块所依赖的任何其他模块的旧版本


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

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

您所做的很酷(实际上您使用的是TDD(测试驱动开发),但您做得不对


通过编写单元测试(使用默认的python模块,或者更好)来考虑这一点与在交互环境中测试模块相比,您可以使用可重用、稳定的测试,帮助您更快更好地检测代码中的不一致性。

这是一件棘手的事情-我有一个工作示例:

从技术上讲,您可以在每个文件中放置重新加载命令,以确保每次导入时都重新加载

a、 py:

b、 py:

现在,以交互方式:

import b
b.testb()
#hi!

#<modify a.py>

reload(b)
b.testb()
#hello again!
导入b
b、 testb()
#嗨!
#
重新加载(b)
b、 testb()
#你好!

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

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
或传递
--deep reload

我遇到过同样的问题,并且我已经建立了@Mattew和@osa answer

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
有三个区别:

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

  • 我发现redsk的答案非常有用。 我提出了一个简化版本(针对用户,而不是代码),其中模块的路径自动收集,递归适用于任意级别。 所有内容都包含在单个函数中。 在Python3.4上测试。我想Python3.3必须
    从imp
    导入重载,而不是从importlib导入重载。 它还检查
    \uuuuuuuuuuuuuuuu文件是否存在,如果编码器忘记在子模块中定义
    \uuuuuuuu init\uuuuuupy
    文件,则该文件可能是错误的。在这种情况下,会引发异常

    def rreload(module):
        """
        Recursive reload of the specified module and (recursively) the used ones.
        Mandatory! Every submodule must have an __init__.py file
        Usage:
            import mymodule
            rreload(mymodule)
    
        :param module: the module to load (the module itself, not a string)
        :return: nothing
        """
    
        import os.path
        import sys
    
        def rreload_deep_scan(module, rootpath, mdict=None):
            from types import ModuleType
            from importlib import reload
    
            if mdict is None:
                mdict = {}
    
            if module not in mdict:
                # modules reloaded from this module
                mdict[module] = []
            # print("RReloading " + str(module))
            reload(module)
            for attribute_name in dir(module):
                attribute = getattr(module, attribute_name)
                # print ("for attr "+attribute_name)
                if type(attribute) is ModuleType:
                    # print ("typeok")
                    if attribute not in mdict[module]:
                        # print ("not int mdict")
                        if attribute.__name__ not in sys.builtin_module_names:
                            # print ("not a builtin")
                            # If the submodule is a python file, it will have a __file__ attribute
                            if not hasattr(attribute, '__file__'):
                                raise BaseException("Could not find attribute __file__ for module '"+str(attribute)+"'. Maybe a missing __init__.py file?")
    
                            attribute_path = os.path.dirname(attribute.__file__)
    
                            if attribute_path.startswith(rootpath):
                                # print ("in path")
                                mdict[module].append(attribute)
                                rreload_deep_scan(attribute, rootpath, mdict)
    
        rreload_deep_scan(module, rootpath=os.path.dirname(module.__file__))
    

    对于Python 3.6+,您可以使用:

    from types import ModuleType
    import sys
    import importlib
    
    def deep_reload(m: ModuleType):
        name = m.__name__  # get the name that is used in sys.modules
        name_ext = name + '.'  # support finding sub modules or packages
    
        def compare(loaded: str):
            return (loaded == name) or loaded.startswith(name_ext)
    
        all_mods = tuple(sys.modules)  # prevent changing iterable while iterating over it
        sub_mods = filter(compare, all_mods)
        for pkg in sorted(sub_mods, key=lambda item: item.count('.'), reverse=True):
            importlib.reload(sys.modules[pkg])  # reload packages, beginning with the most deeply nested
    

    该代码对于导入的依赖项模块非常有效,就像导入另一个\u模块一样,但是当模块从另一个\u模块导入函数时,
    导入一些\u func
    失败

    我扩展了@redsk的答案,尝试对这些函数进行智能化。我还添加了一个黑名单,因为不幸的是,
    键入
    导入库
    没有出现在
    系统中。内置模块名
    (可能还有更多)。我还想防止重新加载我知道的一些依赖项

    我还跟踪重新加载的模块名称并返回它们

    在Python 3.7.4 Windows上测试:

    def-rreload(模块,路径=None,MDCT=None,基本模块=None,黑名单=None,重新加载的模块=None):
    “”“递归地重新加载模块。”“”
    如果路径为“无”:
    路径=[“”]
    如果MDCT为无:
    mdct={}
    如果模块不在MDCT中:
    #从此模块重新加载的模块
    MDCT[模块]=[]
    如果基本模块为无:
    基本模块=模块
    如果黑名单为无:
    黑名单=[“导入库”,“键入”]
    如果重新加载的_模块为无:
    重新加载的_模块=[]
    重新加载(模块)
    重新加载的模块。追加(模块名称)
    对于目录(模块)中的属性名称:
    attribute=getattr(模块、属性名称)
    如果类型(属性)为ModuleType and attribute.\uuuuu name\uuuuuu不在黑名单中:
    如果属性不在MDCT[模块]中:
    如果属性。\名称\不在sys.builtin\模块\名称中:
    如果路径中的os.path.dirname(属性文件):
    MDCT[模块].追加(属性)
    重新加载的\u模块=重新加载(属性、路径、MDCT、基本\u模块、黑名单、重新加载的\u模块)
    elif可调用(属性)和属性。模块不在黑名单中:
    if属性。模块不在sys.builtin\u模块名称和f“{attribute.\uu”mo中
    
    def rreload(module):
        """
        Recursive reload of the specified module and (recursively) the used ones.
        Mandatory! Every submodule must have an __init__.py file
        Usage:
            import mymodule
            rreload(mymodule)
    
        :param module: the module to load (the module itself, not a string)
        :return: nothing
        """
    
        import os.path
        import sys
    
        def rreload_deep_scan(module, rootpath, mdict=None):
            from types import ModuleType
            from importlib import reload
    
            if mdict is None:
                mdict = {}
    
            if module not in mdict:
                # modules reloaded from this module
                mdict[module] = []
            # print("RReloading " + str(module))
            reload(module)
            for attribute_name in dir(module):
                attribute = getattr(module, attribute_name)
                # print ("for attr "+attribute_name)
                if type(attribute) is ModuleType:
                    # print ("typeok")
                    if attribute not in mdict[module]:
                        # print ("not int mdict")
                        if attribute.__name__ not in sys.builtin_module_names:
                            # print ("not a builtin")
                            # If the submodule is a python file, it will have a __file__ attribute
                            if not hasattr(attribute, '__file__'):
                                raise BaseException("Could not find attribute __file__ for module '"+str(attribute)+"'. Maybe a missing __init__.py file?")
    
                            attribute_path = os.path.dirname(attribute.__file__)
    
                            if attribute_path.startswith(rootpath):
                                # print ("in path")
                                mdict[module].append(attribute)
                                rreload_deep_scan(attribute, rootpath, mdict)
    
        rreload_deep_scan(module, rootpath=os.path.dirname(module.__file__))
    
    from types import ModuleType
    import sys
    import importlib
    
    def deep_reload(m: ModuleType):
        name = m.__name__  # get the name that is used in sys.modules
        name_ext = name + '.'  # support finding sub modules or packages
    
        def compare(loaded: str):
            return (loaded == name) or loaded.startswith(name_ext)
    
        all_mods = tuple(sys.modules)  # prevent changing iterable while iterating over it
        sub_mods = filter(compare, all_mods)
        for pkg in sorted(sub_mods, key=lambda item: item.count('.'), reverse=True):
            importlib.reload(sys.modules[pkg])  # reload packages, beginning with the most deeply nested