web-dev-qa-db-ja.com

Pythonモジュールをアンロード(リロード)するにはどうすればいいですか?

私は長期に渡るPythonサーバーを持っていて、サーバーを再起動せずにサービスをアップグレードできるようにしたいです。これを行う最良の方法は何ですか?

if foo.py has changed:
    unimport foo  <-- How do I do this?
    import foo
    myfoo = foo.Foo()
705
Mark Harrison

reload 組み込み関数を使用することで、モジュールが既にインポートされているときにモジュールを再ロードすることができます。

from importlib import reload  # Python 3.4+ only.
import foo

while True:
    # Do some things.
    if is_changed(foo):
        foo = reload(foo)

Python 3では、reloadimp モジュールに移動されました。 3.4では、impimportlib のために非推奨となり、 reload が後者に追加されました。 3以降をターゲットにする場合は、reloadを呼び出すときに適切なモジュールを参照するか、インポートします。

私はこれがあなたが望むものだと思います。 Djangoの開発サーバーのようなWebサーバーはこれを使用するので、サーバープロセス自体を再起動することなくコード変更の影響を見ることができます。

ドキュメントから引用するには:

Pythonモジュールのコードが再コンパイルされ、モジュールレベルのコードが再実行されて、モジュールの辞書内の名​​前にバインドされた新しいオブジェクトのセットが定義されます。拡張モジュールのinit関数が2回呼び出されることはありません。 Pythonの他のすべてのオブジェクトと同様に、古いオブジェクトはそれらの参照カウントがゼロになった後に初めて回収されます。モジュール名前空間の名前は、新しいオブジェクトまたは変更されたオブジェクトを指すように更新されます。古いオブジェクトへの他の参照(モジュールの外部の名前など)は、新しいオブジェクトを参照するようにはリバウンドされず、必要に応じてそれらが発生する各ネームスペースで更新する必要があります。

あなたがあなたの質問で述べたように、あなたはFooクラスがFooモジュールに存在するならば、あなたはfooオブジェクトを再構築しなければなりません。

661
cdleary

Python 3.0〜3.3では、次のように使います。 imp.reload(module)

_ bdfl _ has 回答 この質問。

しかし、 impは3.4で非推奨になりました。importlib のおかげで(ありがとう @Stefan! )。

I think なので、今は importlib.reload(module) を使用しますが、よくわかりませんが。

243
Paul D. Waite

純粋なPythonではない場合、モジュールを削除するのは特に困難です。

ここからいくつかの情報があります: どのように私は本当にインポートされたモジュールを削除するのですか?

Sys.getrefcount()を使用して、実際の参照数を調べることができます。

>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3

3より大きい数字は、モジュールを取り除くのが難しいことを示します。自家製の "empty"(何も含まない)モジュールは後にガベージコレクションされるべきです

>>> del sys.modules["empty"]
>>> del empty

3番目の参照はgetrefcount()関数の成果物です。

82
Gregg Lind

reload(module)が、完全に独立している場合に限ります。他にモジュール(またはそのモジュールに属するオブジェクト)への参照がある場合は、古いコードが予想以上に長くぶら下がっているために発生する微妙で奇妙なエラーが発生します。isinstanceは同じコード.

一方向の依存関係がある場合は、再ロードされたモジュールに依存しているすべてのモジュールを再ロードして、古いコードへの参照をすべて削除する必要があります。そして、再ロードされたモジュールに依存するモジュールを再帰的に再ロードします。

循環的な依存関係がある場合(パッケージの再ロードを扱う場合などに非常に一般的です)、グループ内のすべてのモジュールを一度にアンロードする必要があります。 reload()でこれを行うことはできません。依存関係が更新される前に各モジュールを再インポートし、古い参照が新しいモジュールに入り込むことを可能にするからです。

この場合、それを行う唯一の方法はsys.modulesをハックすることです。これは一種のサポートされていません。次のインポート時にリロードしたい各sys.modulesエントリを確認して削除し、さらに失敗した相対インポートをキャッシュするための実装の問題に対処するために値がNoneであるエントリも削除する必要があります。それはそれほどひどくはありませんが、参照をコードベースの外に残さない完全に自己完結した依存関係のセットを持っている限り、それは実行可能です。

おそらくサーバーを再起動するのが最善です。 :-)

62
bobince
if 'myModule' in sys.modules:  
    del sys.modules["myModule"]
59
Kumaresan

Python 2の場合、組み込み関数 reload() を使用します。

reload(module)

Python 2および3.2から3.3の場合は、 モジュールimp からリロードします。

import imp
imp.reload(module)

しかしimpは非推奨です バージョン3.4以降/ importlibを支持して したがって、以下を使用してください。

import importlib
importlib.reload(module)

または

from importlib import reload
reload(module)
51
goetzc

次のコードはあなたにPython 2/3互換性を与えます:

try:
    reload
except NameError:
    # Python 3
    from imp import reload

どちらのバージョンでもreload()として使うことができ、物事が簡単になります。

21
Matt Clarkson

承認された回答はfrom X import Yケースを処理しません。このコードは、それと標準のインポートケースも処理します。

def importOrReload(module_name, *names):
    import sys

    if module_name in sys.modules:
        reload(sys.modules[module_name])
    else:
        __import__(module_name, fromlist=names)

    for name in names:
        globals()[name] = getattr(sys.modules[module_name], name)

# use instead of: from dfly_parser import parseMessages
importOrReload("dfly_parser", "parseMessages")

リロードの場合は、最上位の名前を新しくリロードされたモジュールに格納されている値に再割り当てします。これにより、それらが更新されます。

16
Joseph Garvin

これはモジュールをリロードする現代的な方法です:

from importlib import reload

MODULEをリ​​ロードしたいモジュールに置き換えて、reload(MODULE)と入力するだけです。

たとえば、reload(math)mathモジュールをリロードします。

14
Richie Bendall

あなたがサーバの中でnotだが開発中であり、頻繁にモジュールをリロードする必要があるなら、ここにNiceのアドバイスがあります。

まず、Jupyter Notebookプロジェクトの優れた IPython Shell を使用していることを確認してください。 Jupyterをインストールした後は、ipythonjupyter console、あるいはさらにjupyter qtconsoleで起動できます。これにより、どのOSでもコード補完機能付きの素敵な色付きコンソールが提供されます。

シェルに入ったら、次のように入力します。

%load_ext autoreload
%autoreload 2

毎回 スクリプトを実行するたびに、モジュールがリロードされます。

2以外にも、自動リロードマジックの他の オプションがあります

%autoreload
Reload all modules (except those excluded by %aimport) automatically now.

%autoreload 0
Disable automatic reloading.

%autoreload 1
Reload all modules imported with %aimport every time before executing the Python code typed.

%autoreload 2
Reload all modules (except those excluded by %aimport) every time before
executing the Python code typed.
10
neves

私のようにすべてのモジュールをアンロードしたい人のために( Emacs の下のPythonインタプリタで実行しているとき):

   for mod in sys.modules.values():
      reload(mod)

より詳しい情報はPythonモジュールのリロードにあります。

7
Arkadiy

Enthought Traitsにはこれにかなりうまくいくモジュールがあります。 https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html

変更されたモジュールを再ロードし、それを使用している他のモジュールとインスタンス化オブジェクトを更新します。ほとんどの場合、__very_private__メソッドではうまくいきませんし、クラスの継承に悩まされることもありますが、PyQt guisやMayaやNukeなどのプログラム内で実行されるものを作成するときにHostアプリケーションを再起動する手間を省けます。たぶん20-30%の時間ではうまくいきませんが、それでも信じられないほど便利です。

Enthoughtのパッケージは変更された瞬間にファイルをリロードしません - あなたはそれを明示的に呼ばなければなりません - しかしあなたが本当にそれを必要とするならそれは実装するのがそれほど難しくないはずです

5
flipthefrog

Python 3を使用していてimportlibからリロードしている人。

モジュールがリロードされないような問題があるのなら...それはpycを再コンパイルするのに時間がかかるからです(最大60秒)。

4
PythonMan

2018-02-01

  1. モジュールfooは事前に正常にインポートされる必要があります。
  2. from importlib import reloadreload(foo)

31.5。 importlib - importの実装 - Python 3.6.4ドキュメント

3
JawSaw

他のオプションPythonのデフォルトのimportlib.reloadは、引数として渡されたライブラリを再インポートするだけです。それは しない あなたのlibがインポートするライブラリをリロードする。たくさんのファイルを変更し、インポートするためにやや複雑なパッケージを持っているなら、 deep reload をしなければなりません。

IPython または Jupyter がインストールされている場合は、すべてのライブラリを深くリロードするための関数を使用できます。

from IPython.lib.deepreload import reload as dreload
dreload(foo)

あなたがJupyterを持っていないなら、あなたのシェルでこのコマンドでそれをインストールしてください:

pip3 install jupyter
3
neves

私にとっては、Abaqusの場合はそれがうまくいく方法です。あなたのファイルがClass_VerticesEdges.pyであると想像してください。

sys.path.append('D:\...\My Pythons')
if 'Class_VerticesEdges' in sys.modules:  
    del sys.modules['Class_VerticesEdges']
    print 'old module Class_VerticesEdges deleted'
from Class_VerticesEdges import *
reload(sys.modules['Class_VerticesEdges'])
1
Matt S

Sublime Text内で何かをリロードしようとすると多くの問題が発生しましたが、最後にsublime_plugin.pyがモジュールのリロードに使用するコードに基づいてSublime Textにモジュールをリロードするこのユーティリティを作成できました。

以下の例では、名前にスペースを含むパスからモジュールをリロードすることができます。その後、リロードした後で、通常どおりインポートすることができます。

def reload_module(full_module_name):
    """
        Assuming the folder `full_module_name` is a folder inside some
        folder on the python sys.path, for example, sys.path as `C:/`, and
        you are inside the folder `C:/Path With Spaces` on the file 
        `C:/Path With Spaces/main.py` and want to re-import some files on
        the folder `C:/Path With Spaces/tests`

        @param full_module_name   the relative full path to the module file
                                  you want to reload from a folder on the
                                  python `sys.path`
    """
    import imp
    import sys
    import importlib

    if full_module_name in sys.modules:
        module_object = sys.modules[full_module_name]
        module_object = imp.reload( module_object )

    else:
        importlib.import_module( full_module_name )

def run_tests():
    print( "\n\n" )
    reload_module( "Path With Spaces.tests.semantic_linefeed_unit_tests" )
    reload_module( "Path With Spaces.tests.semantic_linefeed_manual_tests" )

    from .tests import semantic_linefeed_unit_tests
    from .tests import semantic_linefeed_manual_tests

    semantic_linefeed_unit_tests.run_unit_tests()
    semantic_linefeed_manual_tests.run_manual_tests()

if __== "__main__":
    run_tests()

初めて実行した場合はこれでモジュールがロードされますが、後でメソッド/関数run_tests()を再度実行するとテストファイルが再ロードされます。 Sublime Text(Python 3.3.6)では、そのインタプリタは決して閉じないので(Sublime Textを再起動しない限り、つまりPython3.3インタプリタを除いて)多くのことが起こります。

0
user

もう1つの方法は、モジュールを関数にインポートすることです。このようにして、関数が完了するとモジュールはガベージコレクトされます。

0
hackbot89