36

Python コードを開発するときは、通常、インタープリターでアドホックな方法でテストします。import some_moduleテストしてバグを見つけ、バグを修正して保存し、組み込みreload関数を使用してreload(some_module)再度テストします。

ただし、some_moduleに がimport some_other_moduleあり、テストsome_module中にバグを発見して修正したsome_other_moduleとします。現在、呼び出しreload(some_module)は再帰的に re-import しませんsome_other_module。手動で依存関係を再インポートする必要があります (または、のようなことを行うか、reload(some_module.some_other_module)またはimport some_other_module; reload(some_other_module)、依存関係全体を変更してリロードする必要があるものを見失った場合は、インタープリター全体を再起動する必要があります。

より便利なのは、いくつかのrecursive_reload関数があり、recursive_reload(some_module)Python を reload だけでなく、インポートするすべてのモジュール(およびそれらの各モジュールがインポートするすべてのモジュールなど)some_moduleを再帰的にリロードできるようにすることです。依存some_moduleしている他のモジュールの古いバージョンを使用していなかったと確信できました。some_module

ここで説明する関数のように動作するものは Python に組み込まれていないと思いますが、そのようなrecursive_reloadものを一緒にハックする簡単な方法はありますか?

4

10 に答える 10

35

私は同じ問題に直面しましたが、実際に問題を解決するように促しました。

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

于 2013-06-19T15:08:46.217 に答える
4

モジュールの変更が完了するたびに、実際にいくつかのテストケースを作成して実行する方が簡単ではないでしょうか。

あなたがしていることはクールです(あなたは本質的にTDD(テスト駆動開発)を使用していますが、あなたはそれを間違っています。

書かれた単体テスト(デフォルトのpython unittestモジュールを使用するか、より良いのはnoseを使用)を使用すると、インタラクティブでモジュールをテストするよりもはるかに高速で優れた、再利用可能安定したコードの不整合を検出するのに役立つテストが得られることを考慮してください環境。

于 2013-03-19T17:58:31.037 に答える
4

私は同じ問題に直面し、@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

次の 3 つの違いがあります。

  1. 一般的なケースでは、@osa が指摘したように、関数の最後でも reload(module) を呼び出す必要があります。
  2. 循環インポートの依存関係を使用すると、以前に投稿したコードが永遠にループするため、リストの辞書を追加して、他のモジュールによってロードされた一連のモジュールを追跡しました。循環依存はクールではありませんが、Python では許可されているため、このリロード関数もそれらを処理します。
  3. リロードが許可されているパス (デフォルトは ['']) のリストを追加しました。一部のモジュールは、通常の方法でリロードされることを好みません (ここに示すように)。
于 2015-02-06T04:02:43.360 に答える
1

redsk の回答が非常に役立つことがわかりました。モジュールへのパスが自動的に収集され、再帰が任意の数のレベルで機能する、単純化された (コードとしてではなく、ユーザー向けの) バージョンを提案します。すべてが単一の機能で自己完結しています。Python 3.4 でテスト済み。私はpython 3.3の場合、import reload from imp代わりに... from importlib. また、ファイルが存在するかどうかもチェックします。これは、コード作成者がサブモジュールでファイル__file__を定義するのを忘れた場合に誤りになる可能性があります。__init__.pyこのような場合、例外が発生します。

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__))
于 2016-07-07T10:41:36.103 に答える
1

技術的には、各ファイルに reload コマンドを配置して、インポートするたびに確実にリロードすることができます

a.py:

def testa():
    print 'hi!'

b.py:

import a
reload(a)
def testb():
    a.testa()

さて、インタラクティブに:

import b
b.testb()
#hi!

#<modify a.py>

reload(b)
b.testb()
#hello again!
于 2013-03-19T18:12:29.333 に答える
1

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
于 2019-01-25T16:13:40.247 に答える
-1

これを行うのは難しいことです - 私はこの回答に実際の例を持っています: how to find list of modules that depends on a specific module in python

于 2013-03-19T18:00:47.360 に答える