私は長期に渡るPythonサーバーを持っていて、サーバーを再起動せずにサービスをアップグレードできるようにしたいです。これを行う最良の方法は何ですか?
if foo.py has changed:
unimport foo <-- How do I do this?
import foo
myfoo = foo.Foo()
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では、reload
は imp
モジュールに移動されました。 3.4では、imp
は importlib
のために非推奨となり、 reload
が後者に追加されました。 3以降をターゲットにする場合は、reload
を呼び出すときに適切なモジュールを参照するか、インポートします。
私はこれがあなたが望むものだと思います。 Djangoの開発サーバーのようなWebサーバーはこれを使用するので、サーバープロセス自体を再起動することなくコード変更の影響を見ることができます。
ドキュメントから引用するには:
Pythonモジュールのコードが再コンパイルされ、モジュールレベルのコードが再実行されて、モジュールの辞書内の名前にバインドされた新しいオブジェクトのセットが定義されます。拡張モジュールのinit関数が2回呼び出されることはありません。 Pythonの他のすべてのオブジェクトと同様に、古いオブジェクトはそれらの参照カウントがゼロになった後に初めて回収されます。モジュール名前空間の名前は、新しいオブジェクトまたは変更されたオブジェクトを指すように更新されます。古いオブジェクトへの他の参照(モジュールの外部の名前など)は、新しいオブジェクトを参照するようにはリバウンドされず、必要に応じてそれらが発生する各ネームスペースで更新する必要があります。
あなたがあなたの質問で述べたように、あなたはFoo
クラスがFoo
モジュールに存在するならば、あなたはfoo
オブジェクトを再構築しなければなりません。
Python 3.0〜3.3では、次のように使います。 imp.reload(module)
しかし、 imp
は3.4で非推奨になりました。importlib
のおかげで(ありがとう @Stefan! )。
I think なので、今は importlib.reload(module)
を使用しますが、よくわかりませんが。
純粋な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()関数の成果物です。
reload(module)
が、完全に独立している場合に限ります。他にモジュール(またはそのモジュールに属するオブジェクト)への参照がある場合は、古いコードが予想以上に長くぶら下がっているために発生する微妙で奇妙なエラーが発生します。isinstance
は同じコード.
一方向の依存関係がある場合は、再ロードされたモジュールに依存しているすべてのモジュールを再ロードして、古いコードへの参照をすべて削除する必要があります。そして、再ロードされたモジュールに依存するモジュールを再帰的に再ロードします。
循環的な依存関係がある場合(パッケージの再ロードを扱う場合などに非常に一般的です)、グループ内のすべてのモジュールを一度にアンロードする必要があります。 reload()
でこれを行うことはできません。依存関係が更新される前に各モジュールを再インポートし、古い参照が新しいモジュールに入り込むことを可能にするからです。
この場合、それを行う唯一の方法はsys.modules
をハックすることです。これは一種のサポートされていません。次のインポート時にリロードしたい各sys.modules
エントリを確認して削除し、さらに失敗した相対インポートをキャッシュするための実装の問題に対処するために値がNone
であるエントリも削除する必要があります。それはそれほどひどくはありませんが、参照をコードベースの外に残さない完全に自己完結した依存関係のセットを持っている限り、それは実行可能です。
おそらくサーバーを再起動するのが最善です。 :-)
if 'myModule' in sys.modules:
del sys.modules["myModule"]
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)
次のコードはあなたにPython 2/3互換性を与えます:
try:
reload
except NameError:
# Python 3
from imp import reload
どちらのバージョンでもreload()
として使うことができ、物事が簡単になります。
承認された回答は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")
リロードの場合は、最上位の名前を新しくリロードされたモジュールに格納されている値に再割り当てします。これにより、それらが更新されます。
これはモジュールをリロードする現代的な方法です:
from importlib import reload
MODULE
をリロードしたいモジュールに置き換えて、reload(MODULE)
と入力するだけです。
たとえば、reload(math)
はmath
モジュールをリロードします。
あなたがサーバの中でnotだが開発中であり、頻繁にモジュールをリロードする必要があるなら、ここにNiceのアドバイスがあります。
まず、Jupyter Notebookプロジェクトの優れた IPython Shell を使用していることを確認してください。 Jupyterをインストールした後は、ipython
、jupyter 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.
私のようにすべてのモジュールをアンロードしたい人のために( Emacs の下のPythonインタプリタで実行しているとき):
for mod in sys.modules.values():
reload(mod)
より詳しい情報はPythonモジュールのリロードにあります。
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のパッケージは変更された瞬間にファイルをリロードしません - あなたはそれを明示的に呼ばなければなりません - しかしあなたが本当にそれを必要とするならそれは実装するのがそれほど難しくないはずです
Python 3を使用していてimportlibからリロードしている人。
モジュールがリロードされないような問題があるのなら...それはpycを再コンパイルするのに時間がかかるからです(最大60秒)。
2018-02-01
foo
は事前に正常にインポートされる必要があります。from importlib import reload
、reload(foo)
他のオプションPythonのデフォルトのimportlib.reload
は、引数として渡されたライブラリを再インポートするだけです。それは しない あなたのlibがインポートするライブラリをリロードする。たくさんのファイルを変更し、インポートするためにやや複雑なパッケージを持っているなら、 deep reload をしなければなりません。
IPython または Jupyter がインストールされている場合は、すべてのライブラリを深くリロードするための関数を使用できます。
from IPython.lib.deepreload import reload as dreload
dreload(foo)
あなたがJupyterを持っていないなら、あなたのシェルでこのコマンドでそれをインストールしてください:
pip3 install jupyter
私にとっては、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'])
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
インタプリタを除いて)多くのことが起こります。
もう1つの方法は、モジュールを関数にインポートすることです。このようにして、関数が完了するとモジュールはガベージコレクトされます。