2011-07-04 7 views
2

まず、私がやっていることがPythonicではないと思ったら、別の提案を提供してください。継承を持たないクラスメソッドを上書きする(Python)

私は外部イベントに基づいて機能を変更する必要があるオブジェクトを持っています。私が元々行ってきたことは、元のオブジェクト(それをOrigObject()と呼ぶ)を継承し、変更するメソッドを上書きします(新しいオブジェクトNewObject()を呼び出しましょう)。次に、両方のコンストラクタを変更して、渡されたオブジェクトに基づいて独自の値を埋め込むために、他の型の完全なオブジェクトを取り込むことができます。その後、機能を変更する必要があるときは、myObject = NewObject(myObject)を実行します。

私は今、そのアプローチにいくつかの問題が見え始めています。まず、オブジェクトを参照する他の場所も、新しい型を参照するように更新する必要があります(たとえば、上記のステートメントはローカルのmyObject変数のみを更新します)。しかし、それは更新するのが難しいことではなく、奇妙なプログラムの動作を防ぐために、オブジェクトを変更するたびに別の場所で更新することを覚えているだけです。

第2に、NewObject()の単一のメソッドが必要なシナリオに気づいていますが、OrigObject()の別のメソッドがあり、その機能をオンザフライで切り替える必要があります。私がM * N個の異なるクラスを作る必要があるところでは、継承を使うのは最善の解決策ではないように思えます(Mはクラスが持つメソッドの数です.Nはバリエーションの数です各メソッド)を継承します。OrigObject()

代わりに属性のマッピングを使用することを考えていましたが、問題が発生しているようです。例えば、私はこのような何かを持っていると言う:

def hybrid_type2(someobj, a): 
    #do something else 
    ... 

class OrigObject(object): 
    ... 
    def hybrid_fun(self, a): 
     #do something 
     ... 

    def switch(type): 
     if type == 1: 
      self.hybrid_fun = OrigObject.hybrid_fun 
     else: 
      self.fybrid_fun = hybrid_type2 

問題があり、これをやって、それを切り替えた後、新たなhybrid_funを呼び出そうとした後、私は)(そのhybrid_type2を言って、エラーを取得し、正確に2つの引数を取りますが、私それを渡す。オブジェクトは、自分自身のメソッドと同じように、新しい関数の引数として自分自身を渡しているようには見えません。

ハイブリッドタイプ2をクラス内に含めてから、self.hybrid_fun = self.hybrid_type2を使用しましたが、self.hybrid_fun = OrigObject.hybrid_funを使用すると、最初の引数がOrigObject型である必要があります。私は代わりにOrigObject.hybrid_fun()ロジックをOrigObject.hybrid_type1()の中に定義することができますので、オブジェクトを最初の引数にしないようにするために、クラスに相対的ではなくインスタンスに相対的に設定するのと同じ方法に戻すことができます。しかし私はここには私がここで見ていないよりクリーンなアプローチがあるかどうか質問したかったのですか?おかげで

EDIT: ありがとう、私はうまくいきましたいくつかのソリューションのポイントを与えました。私は本質的にtypes.MethodType()を使ってStrategyパターンを使用してしまったので、PythonでStrategyパターンを実行する方法を説明した答えを受け入れました(Wikipediaの記事はもっと一般的であり、インターフェースの使用はPythonでは不要です) 。

+0

+1クリエイティブなアプローチの場合 – Predator

+0

クラスレベルでメソッドを割り当てる必要があります。次に、それ自身を引数として渡します。 (同じ名前のオブジェクトレベルのメソッドが既に存在する場合は機能しません) - また、「外部イベントに基づいて機能を変更する必要があります」を拡張できますか? ? )より良いアプローチを提供できるかもしれません; – phant0m

答えて

3

は、特定のインスタンスのためのインスタンスメソッドを作成するために、種類のモジュールを使用してください。

例えば、

import types 

def strategyA(possible_self): 
    pass 

instance = OrigObject() 

instance.strategy = types.MethodType(strategyA, instance) 

instance.strategy() 

これはこの特定のインスタンスにのみ影響し、他のインスタンスは影響を受けません。

1

何:

def hybrid_type2(someobj, a): 
    #do something else 
    ... 

def hybrid_type1(someobj, a): 
    #do something 
    ... 

class OrigObject(object): 

    def __init__(self): 
     ... 
     self.run_the_fun = hybrid_type1 

    ... 
    def hybrid_fun(self, a): 
     self.run_the_fun(self, a) 

    def type_switch(self, type): 
     if type == 1: 
      self.run_the_fun = hybrid_type1 
     else: 
      self.run_the_fun = hybrid_type2 
+0

これは、メソッドがバインドされていないために機能しません。 'OrigObject.run_the_fun'にメソッドを割り当てる必要があります。これは、このクラスのすべてのインスタンスの動作を変更します。 – phant0m

+0

@ phant0m [ここ](http://ideone.com/X9nMK)で働くようです。私はそれがバインドされた/アンバインドされたメソッドの面で動作する理由の微妙さを完全に認識していません。私は起こっていることは、self.run_the_funが関数である変数として扱われるということです。 – trutheality

+0

ああ、私はあなたがそれを実行する余分な方法があることに気付かなかった。 'orig_object.run_the_fun(" something ")' – phant0m

2

はPythonでおよそdescriptorsをお読みください。次のコードは動作するはずです:

else: 
    self.fybrid_fun = hybrid_type2.__get__(self, OrigObject) 
+0

これはどのようにして記述子にするのですか? – phant0m

+0

@ phant0m nope。これは 'unbound method'になります –

+0

ああ、私はあなたに彼が記述子を使用したかったと思った。私は今あなたが何を意味するかを見ます。あなたはそれを束縛する方法、つまりNoneの代わりにselfを渡すことを望みます。 – phant0m

0

あなたは、実行時にクラスを変更することができます。

class OrigObject(object): 
    ... 
    def hybrid_fun(self, a): 
     #do something 
     ... 
    def switch(self): 
     self.__class__ = DerivedObject 


class DerivedObject(OrigObject): 
    def hybrid_fun(self, a): 
     #do the other thing 
     ... 
    def switch(self): 
     self.__class__ = OrigObject 
関連する問題