2017-09-21 4 views
2

クラス変数を受け入れることができるクラスでデコレータをセットアップする方法が不思議です。これが役に立つと思う例はPyside/PyQtです。関数の始めと終わりにウィジェットのシグナルをブロックしてブロックを解除する必要があります。クラス変数を渡している間にクラスオブジェクト内の装飾子

例:

class Window(QtGui.QMainWindow): 
    .... 

    def updateList(self, *args): 
     self.list.blockSignals(False) 
     //do things on self.list 
     self.list.blockSignals(True) 

は今、これを行うことができるさまざまなウィジェット上の場所がたくさんの可能性があります。もちろん、私はこの方法で各項目をブロックしたり解除したりすることができますが、それは面倒です。そして、私が済んだら、すべてをブロック解除することを忘れないでください。

別の手順に移動すると、ブロックを自分の機能に移動できます。

class Window(QtGui.QMainWindow): 
    .... 

    def updateList(self, *args): 
     self.block([self.list]) 
     //do things on self.list 
     self.block([self.list]) 

    def block(self, items): 
     for item in items: 
      if item.signalsBlocked(): 
       item.blockSignals(False) 
      else: 
       item.blockSignals(True) 

甘い!私は自分のコードの周りにそれをかけることができ、かなり役に立つと感じています。しかし、私はそれが本当に世界的に有用なものにするためにここで欠けているいくつかの種類の最終的なボスフォームがあるように感じる。デコレータのようなもの。

ここで私のデコレータに変数を渡して、私の関数を飾ることができます! Decorators with parameters?

def block(items): 
    def dec(fn): 
     def wrapped(*args, **kwargs): 
      for item in items: 
       item.blockSignals(True) 
      fn(*args, **kwargs) 
      for item in items: 
       item.blockSignals(False) 
     return wrapped 
    return dec 


class Window(QtGui.QMainWindow): 
    .... 

    @block([self.list]) 
    def updateList(self, *args): 
     //do things on self.list 

今、私はそれが本当に有用である可能性を感じます! @block([self.list])は自己が何であるか分かりません。

私がしようとしていることは、これを行うことができると想定するのは妥当ですか?それは可能ですか、野生の竜を追いかけていますか?可能であれば、これを試みる正しい方法は何ですか?

+0

@DavisHerringああはい、私はもう一度別の答えを見て、私はそれを修正しました。 – ooklah

+0

(コメントのクリーンアップ) –

+0

これはデコレータではなくコンテキストマネージャでなければなりません。どのような特定のオブジェクトや関数/メソッドにも結びついていないので、それはもっと柔軟になります。 – ekhumoro

答えて

2

あなたはクラス定義時に属性にを参照することはできませんが、あなたは自分の名前を使用することができます。

def block(*attrs): 
    def dec(fn): 
     @functools.wraps(fn) 
     def wrap(self,*args,**kwargs): 
      for a in attrs: getattr(self,a).blockSignals(True) 
      ret=fn(self, *args, **kwargs) 
      for a in attrs: getattr(self,a).blockSignals(False) 
      return ret 
     return wrap 
    return dec 

それはで

class Window(QtGui.QMainWindow): 
    @block("list1","list2") 
    def updateList(self, *args): # ... 

を記述する必要がありますし少し醜いです文字列の引用符とすべて、しかしそれは動作します。ここで

+0

私は 'wrap'で' self'の代わりに 'instance'をパラメータ名として使用したと思いますが... – wwii

+0

' instance'はラップされた関数の同じ名前の引数と衝突します。 'wrap'関数は、ディスクリプタが返すとすぐにクラスのメソッドになります。' self'は私にとって完全に慣れているようです。 –

2

は比較のために、シンプルなコンテキストマネージャである:

class blocked(object): 
    def __init__(self, *targets): 
     self._targets = targets 

    def __enter__(self): 
     for target in self._targets: 
      target.blockSignals(True) 

    def __exit__(self, cls, exception, traceback): 
     for target in self._targets: 
      target.blockSignals(False) 

、ここではそれを使用する方法は次のとおりです。

class Window(QtGui.QMainWindow): 
    ... 

    def updateList(self, *args): 
     with blocked(self.list): 
      # do things with self.list 

このようなことをやっての利点はblockedどこでも使用することができるということですであり、ターゲットを動的に指定することができます。ブロックされているのはself.list(シグナルエミッター)であり、self.updateListではなく、より読みやすいという主張も可能です。

+0

私は、信号が機能全体でブロックされてはならない場合に便利な場所をすぐに知ることができます。デコレータは、これらの例では、関数全体を覆い隠すでしょう。 – ooklah

関連する問題