0

次のように、1対多のクラス継承構造があります。

class SuperClass:
  def func1():
    print 'hello'

  def func2():
    print 'ow'

class SubClass1(SuperClass):
   def func1():
     print 'hi'

class SubClass2(SuperClass):
   def func1():
     print 'howdy'

...

クラス A に機能を追加して、クラス B および C (など) を作成するときに使用できるようにしたいのですが、クラス A のコードを直接編集することはできません。私の現在の解決策は次のとおりです。

def func3():
  print 'yes!'

SuperClass.func3 = func3

これを達成するためのより良いおよび/またはよりpythonicな方法はありますか?

4

1 に答える 1

1

これは「モンキーパッチ」と呼ばれ、場合によっては完全に合理的です。

たとえば、 に依存する他の誰かのコード (変更できない) を使用するSuperClass必要があり、そのコードの動作を変更する必要がある場合、唯一の現実的な選択肢は のメソッドを置き換えることSuperClassです。


ただし、あなたの場合、これを行う正当な理由はないようです。のすべてのサブクラスを定義しているSuperClassので、その間に別のクラスを追加してみませんか?

class Intermediate(SuperClass):
    def func3():
        pass

class SubClass1(Intermediate):
    def func1():
        print 'hi'

SuperClassこれは、制御できない他のコードがその機能を必要とする場合、「含まれているはずなのに含まれていなかった機能」には十分ではありません。より簡単です。


サブクラスでさえあなたの管理下にない場合、多くの場合、それぞれのクラスから新しいクラスを派生させることができます. 例えば:

class Func3Mixin(object):
    def func3():
        pass

class F3SubClass1(SubClass1, Func3Mixin):
    pass

class F3SubClass2(SubClass2, Func3Mixin):
    pass

F3SubClass1の代わりに のインスタンスを作成するだけですSubClass1SubClass1インスタンスを期待していたコードは、問題なく使用できますF3SubClass1。そして、Python のダック タイピングは、この種の「ミックスイン指向プログラミング」を特に単純にします。 の実装内では、のFunc3Mixin.func3属性とメソッドを使用できます。であるランタイム オブジェクトも になります。SuperClassFunc3MixinSuperClassFunc3MixinSuperClass


一方、モンキーパッチ適切な場合でも、それが必ずしも最善の答えとは限りません。たとえば、サードパーティ コードのバグを回避するためにパッチを適用している場合、そのコードには優れたライセンスと、独自のパッチを簡単に維持できるソース リポジトリがあり、それをフォークして修正済みコピーを作成できます。 、元の代わりにそれを使用します。


また、記述したとおりに実際に使用できるクラスはないことも指摘しておく価値があります。メソッドを呼び出そうとすると、引数TypeErrorが欠落しているため、エラーが発生します。selfしかし、あなたが にモンキーパッチを当てた方法ではfunc3、 とまったく同じように失敗しfunc1ます。(そして、上でスケッチした代替案についても同じことが言えます。)


最後に、ここにあるすべてのクラスは new-style ではなくクラシック クラスSuperClassですobject。もちろん、 を変更できない場合、それはあなたのせいではありませんが、サブクラス (または ) をおよびから多重継承SuperClassさせることで、とにかく修正したい場合があります。(注意を払っている場合: はい、これは新しいスタイルのクラスを混在させることができることを意味します。ただし、その理由を理解するには、内部ではメタクラスを理解する必要があります。)IntermediateobjectSuperClass

于 2013-04-24T01:37:05.310 に答える