web-dev-qa-db-ja.com

Monkey-patch Pythonクラス

別のモジュールにあるクラスを持っていますが、変更することはできません。

from module import MyClass

class ReplaceClass(object)
  ...

MyClass = ReplaceClass

これは、このファイル以外のMyClassを変更しません。ただし、このようなメソッドを追加する場合

def bar():
   print 123

MyClass.foo = bar

これは機能し、fooメソッドは他のどこでも使用できます。

クラスを完全に置き換えるにはどうすればよいですか?

44
ZooKeeper
import module
class ReplaceClass(object):
    ....
module.MyClass = ReplaceClass
57
Glenn Maynard

from ... import(horrid ;-)最も頻繁に必要なものが修飾名前である場合にベアネームを取得する方法。正しいPythonicな方法で物事を行うと:

import module

class ReplaceClass(object): ...

module.MyClass = ReplaceClass

このように、あなたはmoduleオブジェクトをモンキーパッチングしています。これはあなたが必要とするものであり、そのモジュールが他の人に使用されたときに動作します。とともに from ...形式では、モジュールオブジェクトをhaveしません(ほとんどの人がfrom ...)そして、あなたは明らかに悪化しています;-);

fromステートメントの使用をお勧めする1つの方法は、パッケージ内からモジュールをインポートすることです。

from some.package.here import amodule

そのため、まだモジュールオブジェクトを取得しており、そのモジュール内のすべての名前に修飾名を使用します。

29
Alex Martelli

私は卵です。 。 。 。おそらく、初心者ではないことは明らかですが、私はfrom some.package.module import module 熟語。

GeneralHelpfulClassの1つのメソッドを変更する必要がありました。これは失敗しました:

import some.package.module

class SpeciallyHelpfulClass(some.package.module.GenerallyHelpfulClass): 
    def general_method(self):...

some.package.module.GenerallyHelpfulClass = SpeciallyHelpfulClass

コードは実行されましたが、SpeciallyHelpfulClassにオーバーロードされた動作を使用しませんでした。

これは働いた:

from some.package import module

class SpeciallyHelpfulClass(module.GenerallyHelpfulClass): 
    def general_method(self):...

module.GenerallyHelpfulClass = SpeciallyHelpfulClass

from ... importイディオムは、パッケージ内の他のモジュールによって取得されるため、Alexが書いたように「モジュールを取得」します。さらに推測すると、長い点線の参照は、長い点線の参照によるインポートでモジュールを名前空間に持ち込むように見えますが、他の名前空間で使用されるモジュールは変更しません。したがって、インポートモジュールへの変更は、変更が行われた名前空間にのみ表示されます。同じモジュールのコピーが2つあり、それぞれがわずかに異なる参照で利用できるかのようです。

12
chernevik
_import some_module_name

class MyClass(object): 
     ... #copy/paste source class and update/add your logic

some_module_name.MyClass = MyClass
_

何らかの理由でgetattrを使用してそれらを参照している可能性があるため、置換中にクラスの名前を変更しないことをお勧めします-以下のように失敗します

getattr(some_module_name, 'MyClass')-> MyClassをReplaceClassに置き換えた場合は失敗します!

0
shahjapan