3

私は、接続関数を使用してシグナルをシグナルハンドラーに接続できるGUIライブラリを使用しています。次に例を示します。

widget.connect(signal, callback)

callbackウィジェットからシグナルが発生するたびに関数が実行されることを意味します。コードをより適切にし、コンストラクターから一連のconnect呼び出しを削除するために、デコレーターを使用することにしました。これはうまく機能します。

def callback(widget, signal)
    def decorate(f):
            widget.connect(signal, f)
            return f
    return decorate

...

@callback(widget, signal)
def do_something():
    ...

これは、クラスでこれを行う必要があるまではうまく機能します。関数は、クラスにバインドされる前に装飾されます。つまり、指定されたコールバック関数は、それを所有するクラスのインスタンスを取得せず、役に立たなくなります。これを機能させる方法はありますか?

4

1 に答える 1

2

これに対する比較的簡単な解決策が可能です。まず、デコレータを使用して関数をマークします。インスタンスが構築されると、これらのマークを検索してコールバックを登録します。

より具体的には、マークと再キャプチャのパターンは、デコレータを使用して、バインドされる前に関数にマークを付け、コンストラクター内のインスタンスのバインドされたメソッドの中からそれを見つけることによって機能します。

まず、デコレータを使用してマーキングを行います(1つのメソッドで複数のマークを使用できるようにセットを使用します)。

def callback(*args):
    def decorate(f):
        try:
            f._marks.add(args)
        except AttributeError:
            f._marks = {args}
        return f
    return decorate

次に、inspectモジュールを使用して、マークされた関数のバインドされたバージョンを見つけ、それらを接続します。

def connect_callbacks(obj):
    for _, f in inspect.getmembers(obj, inspect.ismethod):
        try:
            marks = f.__func__._marks
        except AttributeError:
            continue
        for widget, signal in marks:
            widget.connect(signal, f)

__func__元のバインドされていない関数の名前です。これにより、以前に適用したマークにアクセスできるようになり、再キャプチャが容易になります。

次に、クラスを作成して関数を装飾し、コンストラクターでコールバックを接続することを忘れないでください。

class Test:
    def __init__(self):
        ...
        connect_callbacks(self)

    @callback(widget, signal)
    def test():
        ...

これにより、バインドされたメソッドをデコレータに接続できます。

編集:私はあなたのためにこれを行う小さなライブラリをgithubに公開しました-それは要約と呼ばれています。

于 2012-08-22T18:03:18.757 に答える