Python: 'from X import Y'でインポートされたコンポーネントYをリロードしますか?


91

Pythonでは、インタープリターセッションでモジュールXをインポートしたら、 import Xが外側で変更されたら、でモジュールを再ロードできますreload(X)。その後、変更は通訳者セッションで使用可能になります。

を使用してモジュールXからコンポーネントYをインポートするときにもこれが可能かどうか疑問に思っています from X import Yます。

ステートメント reload YYはモジュール自体ではなく、モジュール内のコンポーネント(この場合はクラス)だけなので、は機能しません。

インタプリタセッションを終了せずに(またはモジュール全体をインポートせずに)モジュールの個々のコンポーネントをリロードすることはまったく可能ですか?

編集:

明確にするために、問題はモジュールXからクラスまたは関数Yをインポートし、パッケージXからモジュールYではなく、変更時にリロードすることです。


私はこの質問に矛盾があると信じています: " ... possible ... import a component Y from module X" vs " question is ... importing a class or function X from a module Y"。そのエフェクトに編集を追加しています。
Catskul 2012

マークされた答えは実際には質問に答えていないようです、私はそう思います。更新/コメントできますか?
Catskul 2014年

回答:


49

Yがモジュール(およびXがパッケージ)のreload(Y)場合は問題ありません-そうでない場合は、優れたPythonスタイルガイド(私の雇用主など)がモジュール以外をインポートしないと言う理由がわかります(これは多くの大きな理由の1つです) -それでも、人々がまだ関数とクラスを直接インポートし続けている、それがどれほど良い考えではないと私が説明しても、;)


1
あなたの言ってる事がわかります。それが良いアイデアではない理由を他の理由で詳しく説明してもらえますか?
cschol 2009年

6
@cschol:PythonのZen、最後の詩(import thisPythonのZenを表示するインタラクティブプロンプトから); そしてすべての理由なぜ名前空間がモジュールは、予測可能かつ制御可能ないくつかのエントリを再定義することにより、柔軟に変更するために鳴らし素晴らしいアイデア(名前のが検索されることをすぐに地元の視覚的な手がかり、モックのしやすさ/テストに注入し、リロードする機能、能力がありますデータのシリアライゼーションとリカバリの動作[[ピクル処理とアンピクル処理]など]など-SOコメントは、この豊富で長い議論を正当化するのに十分な長さではありません!!!-)
Alex Martelli

4
Python 3では、reloadはデフォルトのネームスペースに存在しなくなりましたが、importlibパッケージに移動されました。 importlib.reload(Y) docs.python.org/3.4/library/...はも参照してくださいstackoverflow.com/questions/961162/...
ハエ

4
@ThorSummoner、絶対にそうではありません-「常にモジュールをインポートする」を意味するので、「from my.package import mymodule」は絶対にうまく、実際に好まれます-クラス、関数などをインポートしないでください-常に、常に、常にモジュール
Alex Martelli、2015年

2
反対票。どうして?これは正しい答えではありません。正解は、Catskulによって12年7月30日15:04に出された。
meh

102

回答

私のテストから、単純なを示唆するマークされた回答reload(X)が機能しません。

私が正しい答えを言うことができることから:

from importlib import reload # python 2.7 does not require this
import X
reload( X )
from X import Y

テスト

私のテストは次のとおりでした(Python 2.6.5 + bpython 0.9.5.2)

X.py:

def Y():
    print "Test 1"

bpython:

>>> from X import Y
>>> print Y()
Test 1
>>> # Edit X.py to say "Test 2"
>>> print Y()
Test 1
>>> reload( X )  # doesn't work because X not imported yet
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'X' is not defined
>>> import X
>>> print Y()
Test 1
>>> print X.Y()
Test 1
>>> reload( X ) # No effect on previous "from" statements
>>> print Y()
Test 1
>>> print X.Y() # first one that indicates refresh
Test 2
>>> from X import Y
>>> print Y()
Test 2 
>>> # Finally get what we were after

1
ワオ。これは本当に重宝しました。ありがとう!これを1つのライナーとして使用します。reload(X); XからのインポートY
otterb 14

1
これは受け入れられたものよりも良い答えです。人々に警告するのは公平ですが、すべての人のユースケースは異なります。場合によっては、クラスをリロードすると本当に便利です。たとえば、Pythonコンソールを使用していて、セッションを失うことなくコードの変更をロードしたい場合などです。
nicb 2017

これは常に機能するとは限りません。サブモジュールをフェッチするFooを持つモジュールがあり__init__.pyます...反例として回答を投稿します。
Jason S

Python 3ワンライナー:import importlib; import X; importlib.reload(X); XからのインポートY
Wayne

12
from modulename import func

import importlib, sys
importlib.reload(sys.modules['modulename'])
from modulename import func

あなたはそれがインポートされた正確にどのように覚えていない可能性がありますので、これは芋の最良の方法である
portforwardpodcast

これが元の質問に対する唯一の有効な解決策であり、投票数が少なすぎます!
CharlesB

1
Python 3で追加:importlibからimport reload
mirek

7

まず、回避できる場合は、リロードを使用しないでください。しかし、あなたにはあなたの理由があると仮定しましょう(すなわち、IDLE内でのデバッグ)。

ライブラリを再ロードしても、名前はモジュールの名前空間に戻されません。これを行うには、変数を再割り当てします。

f = open('zoo.py', 'w')
f.write("snakes = ['viper','anaconda']\n")
f.close()

from zoo import snakes
print snakes

f = open('zoo.py', 'w')
f.write("snakes = ['black-adder','boa constrictor']\n")
f.close()

import zoo
reload(zoo)
snakes = zoo.snakes # the variable 'snakes' is now reloaded

print snakes

他のいくつかの方法でこれを行うことができます。ローカルの名前空間を検索し、問題のモジュールからのものを再割り当てすることで、プロセスを自動化することもできますが、私たちは十分に悪いことだと思います。


4

これを行いたい場合:

from mymodule import myobject

代わりにこれを行ってください:

import mymodule
myobject=mymodule.myobject

これで、計画したのと同じ方法でmyobjectを使用できます(面倒な読み取り不可能なmymodule参照はどこにもありません)。

インタラクティブに作業していて、myobjectをmymoduleから再ロードする場合は、次のように使用できます。

reload(mymodule)
myobject=mymodule.myobject

2

を使用した場合from X import Y、2つのオプションがあります。

reload(sys.modules['X'])
reload(sys.modules[__name__]) # or explicitly name your module

または

Y=reload(sys.modules['X']).Y

いくつかの考慮事項:

A.インポートスコープがモジュール全体ではない場合(たとえば、関数でのインポート)-2番目のバージョンを使用する必要があります。

B. Yが別のモジュール(X)からXにインポートされる場合-Zを再ロードする必要があります。Xを再ロードしてからモジュールを再ロードしてください。すべてのモジュールを再ロードしても(たとえば、を使用して[ reload(mod) for mod in sys.modules.values() if type(mod) == type(sys) ])、Zを再ロードする前にXを再ロードする可能性があります。 Yの値を更新しません。


1
  1. reload()モジュールX
  2. reload()YからインポートするモジュールX

リロードしても、他の名前空間にバインドされている作成済みのオブジェクトは変更されないことに注意してください(Alexのスタイルガイドに従っても)。


1

ジュピター環境で作業していて、すでにfrom module import functionマジック関数を使用している場合はautoreload

%load_ext autoreload
%autoreload
from module import function

autoreloadIPython での紹介はここにあります


0

AlexMartelliCatskulの回答をフォローアップするためreloadに、少なくともPython 2では、いくつかの本当にシンプルだが厄介なケースが混同しているように見えます。

次のソースツリーがあるとします。

- foo
  - __init__.py
  - bar.py

次の内容で:

init.py:

from bar import Bar, Quux

bar.py:

print "Loading bar"

class Bar(object):
  @property
  def x(self):
     return 42

class Quux(Bar):
  object_count = 0
  def __init__(self):
     self.count = self.object_count
     self.__class__.object_count += 1
  @property
  def x(self):
     return super(Quux,self).x + 1
  def __repr__(self):
     return 'Quux[%d, x=%d]' % (self.count, self.x)

これは使用せずにうまくいきreloadます:

>>> from foo import Quux
Loading bar
>>> Quux()
Quux[0, x=43]
>>> Quux()
Quux[1, x=43]
>>> Quux()
Quux[2, x=43]

しかし、リロードしてみてください。効果がないか、壊れています。

>>> import foo
Loading bar
>>> from foo import Quux
>>> Quux()
Quux[0, x=43]
>>> Quux()
Quux[1, x=43]
>>> reload(foo)
<module 'foo' from 'foo\__init__.pyc'>
>>> Quux()
Quux[2, x=43]
>>> from foo import Quux
>>> Quux()
Quux[3, x=43]
>>> reload(foo.bar)
Loading bar
<module 'foo.bar' from 'foo\bar.pyc'>
>>> Quux()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "foo\bar.py", line 17, in __repr__
    return 'Quux[%d, x=%d]' % (self.count, self.x)
  File "foo\bar.py", line 15, in x
    return super(Quux,self).x + 1
TypeError: super(type, obj): obj must be an instance or subtype of type
>>> Quux().count
5
>>> Quux().count
6
>>> Quux = foo.bar.Quux
>>> Quux()
Quux[0, x=43]
>>> foo.Quux()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "foo\bar.py", line 17, in __repr__
    return 'Quux[%d, x=%d]' % (self.count, self.x)
  File "foo\bar.py", line 15, in x
    return super(Quux,self).x + 1
TypeError: super(type, obj): obj must be an instance or subtype of type
>>> foo.Quux().count
8

barサブモジュールが確実にリロードされるようにする唯一の方法はreload(foo.bar)、再読み込みされたQuuxクラスにアクセスする唯一の方法は、再読み込みされたサブモジュールに到達してそれを取得することです。ただし、fooモジュール自体が元のQuuxクラスオブジェクトを保持し続けました。これは、おそらくfrom bar import Bar, Quux(後にがimport bar続くのではなくQuux = bar.Quux)使用するためです。さらに、Quuxクラスはそれ自体と同期しなくなりました。これは奇妙です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.