2013-03-19 1 views
16

私はPythonコードを開発しているときに、通常はインタプリタの特別な方法でテストします。私はimport some_moduleにテストし、バグを発見し、バグを修正して保存してから、reloadの組み込み関数を使ってreload(some_module)に戻り、もう一度テストします。'reload'の再帰的バージョン

しかし、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)のようなものを実行するか、依存関係の全部を変更して再ロードする必要があるトラックを失った場合は、インタープリタ全体を再起動する必要があります)。

What'dは、より便利に、いくつかのrecursive_reload機能があった場合であり、私はちょうどrecursive_reload(some_module)を行うと、Pythonがsome_moduleをリロードするだけでなく、再帰的にsome_module輸入(およびそれらのモジュールの輸入の各モジュールごとこと、すべてのモジュールをリロードするだけでなく持つことができますなど)、私がsome_moduleが依存する他のモジュールの古いバージョンを使用していないことを確かめることができます。

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

+0

[Pythonで特定のモジュールに依存するモジュールのリストを検索する方法]の可能な重複(http://stackoverflow.com/questions/1827629/how-to-find-list-of-modules-特定のモジュールに依存しているPython) – jsbueno

答えて

21

私は同じ問題に直面して実行した、とあなたは、実際に問題を解決するために私に影響を与えました。

from types import ModuleType 

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を渡します。

+2

これを受け入れることはできませんが、最初はお互いに依存していない 'moduleA'と' moduleB'が両方ともインポートされていれば'moduleA'が' import moduleB'に変更された場合、 'rreload(moduleA)'を呼び出すと 'moduleB'を再ロードしません。 これは私がこれを使用する場合には私にとって重要ではない小さなマイナーな問題です。 –

+1

「reload(module)」を関数の先頭に移動することで、この問題を解決できることが分かります。 –

+0

実際、私はそれを実験しているので、 'reload(module)'を2回呼び出すことがあります。サブモジュールをリロードする前と後。新しいモジュールを参照する場合は、前に呼び出す必要があります。 'from X import Y'などの文を処理するには、後で呼び出す必要があります。 'X'がリロードされたばかりの場合、' Y'を再インポートする必要があります。私はそれがはるかに扱いにくいかもしれないと思うので、ほこりが落ち着くまでリロードを続ける必要があります。 – osa

3

実際にいくつかのテストケースを書き、モジュールを修正するたびに実行するのは簡単ではないでしょうか?

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

は検討することをデフォルトのpythonより良いまだunittestモジュール、またはを使って書かれたユニットテスト(とnose)あなたはより速く、よりインタラクティブな環境で、あなたのモジュールをテストするとより良いはるか安定再利用可能なあるテストを持って取得すると、あなたのコード内でinconsitenciesを検出するのに役立つ。

+0

+1、このテスト方法が抜けているようです。実際のケースである必要はなく、コードをテストするためのスクラッチパッドとして保持する小さなスクリプトを用意するだけです(プロジェクトの規模が十分に小さく、十分なテストが残忍である場合)。 –

+2

アイロニー:私は別のアプリケーション*のために書いていたいくつかのユニットテストをテストしながら、この問題を打つ*後にこの質問をするように誘惑されました。ここであなたのアドバイスを適用すると、無限に繰り返され、無限のテストレイヤーが作成されます。 ;) –

+2

もっと真剣に:当然のことながら、適切なテストが行​​われていますが、時にはより適切なテストが必要ではなく、それに加えて、もっとカジュアルなアプローチが求められます。そのカジュアルなアプローチは簡単です。たぶん私は関数の半分を書いて、今のところ私が期待しているものを出力しているのか、それとも多少の印刷ステートメントをちょっとしたコードに詰め込んだだけで、私は何が印刷されるのかを指定して見ます。ユニットテストは、これらのシナリオには適用されません。 –

0

行うにはトリッキーなものである - 私はこの答えで働く例があります。 how to find list of modules which depend upon a specific module in python

+0

コードを読んで理解しようとしませんでしたが、defsをインタプリタに貼り付け、モジュールのreload_dependencesを呼び出してみました: 'トレースバック(最新の呼び出し最後): ファイル" "、行1、 ファイル ""、行9、reload_dependences ImportError:内部モジュール__main__を再起動できません –

+0

まあ、エラーメッセージは、 "__main__"モジュール自体を再試行しようとしていると思いますセッション。そのコードを別のファイルに貼り付けてitnerpreter IIRCにインポートしてみてください。 – jsbueno

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! 
+1

確かに、私はこれを行うことができましたが、私の実際のコードファイルは醜く非効率的でした。私はインタラクティブなインタプリタで遊んでいるときに馬鹿げたハックを使用しても構いませんが、私のコードですべてのファイルに馬鹿げたハックを導入しないようにしたいと思います。 。 :) –

1

私は同じ問題に対して実行しました。私は@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が指摘したように、同様の機能の終了時に呼び出されなければなりません。
  2. 循環インポートの依存関係では、以前にポストされたコードは永遠にループするため、他のモジュールによってロードされたモジュールのセットを追跡するためのリストの辞書を追加しました。循環依存はクールではありませんが、Pythonはそれらを許可します。したがって、このリロード機能も同様です。
  3. リロードが許可されているパスのリストを追加しました(デフォルトは[''])。いくつかのモジュールは通常の方法で再ロードされたのが好きではありません(here)。
+0

関数内で変更するdictの既定のパラメーターがあるため、関数を2回呼び出すと同じdictが使用され、何もリロードされません。 –

+0

rreload関数を呼び出すたびに、mdictディクショナリはゼロから塗りつぶされます。私は現在、この関数を使用しています。私はコードを変更するたびに通話を定期的に呼び出すので(インタープリタを再ロードせずに複数回も)、動作します... – redsk

1

私はredskの回答が非常に役に立ちました。 私は、モジュールへのパスが自動的に集められ、任意の数のレベルで再帰が機能する単純化された(コードではなく、ユーザーにとって)バージョンを提案します。 すべてが1つの機能で自己完結型です。 Python 3.4でテスト済みです。私はPython 3.3の場合、importlibの代わりにimpからreload()をインポートしなければならないと思います。 また、ファイルファイルが存在するかどうかをチェックします。サブフォルダに .pyファイルを定義することをコーダーが忘れた場合はfalseになることがあります。そのような場合、例外が発生します。

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__))