オブジェクトがあり、そのメソッドの1つをPyQtシグナルが発行されたときに実行したいとします。そして、私はそれが信号によって渡されないパラメータでそうしたいと仮定します。だから私は、信号のスロットとしてラムダ作成:通常のPyQtのシグナルとスロットで、今ラムダのオブジェクトのライフタイムがpyqtSignalに接続されている
class MyClass(object):
def __init__(self, model):
model.model_changed_signal.connect(lambda: self.set_x(model.x(), silent=True))
を、信号接続は、ガベージコレクションを防ぐことはできません。接続されたスロットのオブジェクトがガーベッジ・コレクションされると、対応する信号が放出されたときにスロットはもはや呼び出されなくなります。
しかし、lambdaを使用するとどのように動作しますか?私はラムダへの参照を格納していませんが、シグナルスロット接続は機能し続けます。したがってラムダはガベージコレクションされません。
MyClass
のインスタンスをNone
に設定すると、そのインスタンスはガベージコレクションされません。model_changed_signal
を発行すると、ラムダは正常に実行されます。だから明らかに、MyClass
のインスタンスへの参照はどこかで(おそらくラムダの文脈で)保持されています - 私は望んでいません。
どうしてですか?
これは、ラムダによってMyClassとMyModelへの参照を保持することを確認し、明確にしてくれてありがとう!残念なのは、ラムダのガベージコレクションが他の関数オブジェクトと異なる理由です。クラスをインスタンス化し、メソッドの1つを次のように接続するとします。 'model.model_changed_signal.connect(ModelListener()。handle_signal)'、 'ModelListener'のインスタンスはガベージコレクトされ、' handle_signal'は決してされませんと呼ばれる。 – tjalling
@tjalling。ラムダの場合、ガベージコレクションはまったく同じです。その違いは完全にクロージャによるものであり、*任意の*関数がそれらのうちの1つを形成することができます。関数ではなく、余分な参照を保持するのはクロージャです。あなたのコメントに与えられた例ではクロージャはありません。 – ekhumoro
しかし、クロージャーへの参照が必要なのでしょうか?ラムダへの最後の参照を捨てると(例えば 'None'に設定することによって)、ラムダと対応するクロージャーはガベージコレクションされますか?ラムダを 'pyqtSignal'に接続するとラムダ(およびクロージャ)がガーベジコレクションされるのを防ぐのに対して、バインドされた関数をシグナルに接続しても、そのオブジェクトが(その関数がバインドされている)集めました? – tjalling