2015-09-28 13 views
6

が、私はそれが私の猿を行う方法RealクラスPythonの:どのようにモンキーパッチ(スワップ)クラス

from a import Real 
Real().print_stuff() 

を使用するモジュールで、次の2つのクラスモジュールba

class Real(object): 
    ... 
    def print_stuff(self): 
     print 'real' 

class Fake(Real): 
    def print_stff(self): 
     print 'fake' 

を考えてみましょうしますパッチを適用してbをインポートするとRealが実際にFakeと交換されますか?

初期化スクリプトでこれを行うようにしようとしていましたが、動作しません。

if env == 'dev': 
    from a import Real, Fake 
    Real = Fake 

私の目的は、開発モードでFakeクラスを使用することです。

+0

この初期化スクリプトとは、元のプログラムの先頭で実行される別の '.py'スクリプトです。 –

+0

はい、これはDjangoアプリです。そのため、initスクリプトはapp.pyにありますが、これは一般的な目的では言及していませんでした。 –

答えて

2

問題は、あなたが行うときということです -

from a import Real, Fake 

あなたは基本的にあなたのinitializeスクリプトの名前空間にこれら2つのクラスをインポートし、initializeスクリプトの名前空間にRealFake名を作成しています。その後、のスクリプトのFakeを指しますが、実際のaモジュールでは何も変更されません。

initializeスクリプトは、あなたが以下使用することができ、あなたの元のプログラムの開始時に実行時、別の.pyのモジュール/スクリプトの場合 - これはa.RealFakeクラスを参照するようになるだろう、注意してください

if env == 'dev': 
    import a 
    a.Real = a.Fake 

を上記の行が実行された後に、aモジュールからRealを使用するたびに実行されます。


私はと、そのモジュールにenvをチェックすることが可能となることで、あなたのaモジュール自体でこれを行うには良い方法であることを示唆しているだろうけど -

if <someothermodule>.env == 'dev': 
    Real = Fake 

コメントで尋ねられたように -

初期化スクリプトの名前空間にもインポートをインポートしませんか?モジュールとクラスのインポートの違いは何ですか?事はあなたがfrom a import classを使用して、単にクラスをインポートするときに、あなたが実際に行うことを指すように、その変数を変更し、(あなたはそれがインポートモジュールで)あなたのモジュールの名前空間でclass、その変数を作成するということです

そのモジュールの名前空間で新しい何かが元のモジュールオブジェクトの元のクラスに影響を及ぼさず、変更されたモジュールでのみ影響を受けます。

しかし、あなたはimport aを行うときに、あなただけのモジュールaをインポートしている(ともsys.modules辞書にキャッシュされますモジュールオブジェクトをインポートするとき、その任意の他のモジュールからaに他の輸入がsys.modulesから、このキャッシュされたバージョンになるだろう) (別の言葉では、from a import somethingも内部でaをインポートし、それをsys.modulesにキャッシュしていますが、ここでは必要ないと思われるので、これらの詳細には入りません)。

そして、あなたはa.Real = <something>、あなたが何か他のものに、クラスを指すaモジュールオブジェクトのReal属性を変更しているんときに、これは直接aモジュールを変異させる、それゆえ変更も反映され、モジュールはa他のモジュールからインポートされます。

+0

私が 'a'モジュールの中でそれを行うと、それはモジュール' a'の中に埋め込まれ、他人が何が起こっているのかを理解することは難しいでしょうか?モジュール 'a'はライブラリです。 –

+0

確かに 'a'が非常に大きければ可能ですが、問題の代わりに' a'をつぶしている 'init'モジュールが' a'自体にあることを人々が理解することは難しいでしょう。私が新しい開発者だと言うと、私はコードを実行し、 'a'から' Real'を呼び出そうとしているときに偽のクラスを取得しているのを見て、 'a'でコードをチェックし、' Real 'が' Fake'によって上書きされている場合、 'init'モジュールが' a.Real'を 'a.Fake'に変更していることを推測することは非常に難しいでしょう。同意しますか? –

+0

私はPythonのインポートにかなり悩んでいます。 'import a'も' initialize'スクリプトの名前空間にインポートしませんか?モジュールとクラスのインポートの違いは何ですか? –

3

mockモジュールのpatchを使用できます。次に例を示します。

with patch('yourpackage.b.Real') as fake_real: 
    fake_real.return_value = Fake() 
    foo = b.someClass() 
    foo.somemethod() 
+0

あなたのコードは、そのコンテキスト内でのみ動作しますか?この場合、単体テストの目的にパッチを当てていません。 –

関連する問題