2011-07-21 6 views
8

_wrap_runメソッドでラップされるrunメソッドでオブジェクトを作成しようとしています。私はメソッドを呼び出すことができるようにしたいと単純にinstance.runを入力してラッパー()と私はrun()メソッドをオーバーライドすることができ、それはまだラッパーを実行するオブジェクトをサブクラス化できるようにしたいと思います。Python Wrapクラスメソッド

もっと単純に言えば、人々はAをサブクラス化してrun()をオーバーライドできますが、run()メソッドを呼び出すとラッパー関数を実行できるようにします。

私はこれの仕組みにいくつかの問題があります。誰もこのアプローチに関する提案はありますか?読んでくれてありがとう。

class A: 

    def run(self): 
     print "Run A" 
     return True 

    def _wrap_run(self): 
     print "PRE" 
     return_value = self.run() 
     print "POST" 
     return return_value 

    run = property(_wrap_run) 


a = A() 
a.run() 
""" 
Should Print: 
PRE 
Run A 
POST 
""" 


class B(A): 

    def run(self): 
     print "Run B" 
     return True 

b = B() 
b.run() 
""" 
Should Print: 
PRE 
Run B 
POST 
""" 
+1

'_wrap_run'のポイントは何ですか?これはある種のデコレータになっていますか?これにデコレータを使用すると何が問題になりますか? –

+1

彼はすべての派生クラスを飾る必要はありません。 – agf

答えて

12

メタクラスを使用します。

class MetaClass(type): 
    @staticmethod 
    def wrap(run): 
     """Return a wrapped instance method""" 
     def outer(self): 
      print "PRE", 
      return_value = run(self) 
      print "POST" 
      return return_value 
     return outer 
    def __new__(cls, name, bases, attrs): 
     """If the class has a 'run' method, wrap it""" 
     if 'run' in attrs: 
      attrs['run'] = cls.wrap(attrs['run']) 
     return super(MetaClass, cls).__new__(cls, name, bases, attrs) 

class MyClass(object): 
    """Use MetaClass to make this class""" 
    __metaclass__ = MetaClass 
    def run(self): print 'RUN', 

myinstance = MyClass() 

# Prints PRE RUN POST 
myinstance.run() 

今、他の人がMyClassをサブクラス化する場合、彼らはまだ彼らのラップrun()メソッドを取得します。

+0

これは本当にクールなアプローチであり、うまく機能しているようです。 –

3

最も簡単な方法:runラッパーを作り、プライベートメソッドはoverrideable一つです。あなたは基本的にdecoratorあり持っているので、機能をサブクラス化する際に、なぜ先に行くと、デコレータとして_wrap_runを実装し、それを適用していない何

class A(object): 
    def run(self): 
     print "PRE" 
     return_value = self._inner_run() 
     print "POST" 
     return return_value 

    def _inner_run(self): 
     print "Run A" 
     return True 

class B(A): 
    def _inner_run(self): 
     print "Run B" 
     return True 
+0

ご意見ありがとうございます。サブクラスでrun()を実装している人が余分な呼び出しを心配する必要がなく、関数呼び出しを適切に追加するためにそれらに依存するようにしたいと思います。さらに、下線付きのラッパー関数は、私が子クラスから隠しておきたいメンテナンス作業を行っています。私が求めていることがうまくいくかどうかは分かりませんが... –

+0

@JoeJ:インタフェースを適切に文書化してください。サブクラスが 'run'などをオーバーライドする必要があるかどうかは関係ありません。 –

+0

@Joe: 'run'ではなく' FormEncode '_to_python'(http://formencode.org/Validator.html?highlight=_to_python)など、ユーザーが' _run'をオーバーライドできるようにするのは非常に一般的です。 – neurino

1

+0

私はデコレータを作成することを考えていますが、親クラスでデコレータを追加する必要がないように、親クラスでデコレータを追加する必要はありません。 –

+0

いいえ、それはPythonの略です –

+0

私はそれがPythonの略である__exactly__だと思います。ダックタイピングやコンテキストマネージャとはどのように違いますか?私は 'run()'を簡単な方法で書くことができ、メタクラスは細部を処理します。 – agf

1

他の人々は通常は十分だ

class A: 
    def do_run(self): 
     """Must be overridden.""" 
     raise NotImplementedError 
    def run(self, *args, **kw): 
     """Must not be overridden. 
     You were warned. 
     """ 
     print "PRE" 
     return_value = self.do_run(*args, **kw) 
     print "POST" 
     return return_value 

class B(A): 
    def do_run(self): 
     print "Run B" 
     return True 

を何。

誰かがこれを「壊す」ことを心配したい場合は、今すぐ停止してください。心配する時間を無駄にしないでください。

It's Python。私たちはすべてここで大人です。すべての悪意のある社会病者は、あなたのコードをコピーして変更し、それを破ることによって、すべてのコードを破壊します。あなたが何をしていても、彼らはあなたのコードをコピーし、巧妙なビットを壊すためにそれを変更するだけです。

他の人はあなたのコメントを読んだり、あなたのルールに従います。彼らがあなたのモジュール/パッケージ/フレームワークを使いたいなら、彼らは協力するでしょう。

+0

'run()'は引数を受け入れる必要のある 'do_run()'を呼び出す必要があります。 – agf

+0

ありがとうS.Lott。それはストレートフォワードアプローチのようだ。ええ、私はいくつかのコメントが十分にあると思います。 –

+0

@Joe J:** **十分です。本当に何もできることはありません。より複雑なものはメンテナンスの頭痛だけです。どのくらいの余分なコードを書いても、誰かがいつもそれを混乱させるでしょう。だからあなたが逃げることのできる最小のコードを書いてください。 –

関連する問題