О жизненном цикле лямбда PyQt [дубликат]

Оператор == всегда предназначен для сравнения ссылок на объекты, тогда как метод сравнения строк .equals () переопределяется для сравнения содержимого:

String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // It prints false (reference comparison)
System.out.println(s1.equals(s2)); // It prints true (content comparison)
2
задан ekhumoro 22 December 2017 в 19:43
поделиться

1 ответ

lambda в вашем примере образует закрытие. То есть, это вложенная функция, которая ссылается на объекты, доступные в охватывающей области. Каждая функция, которая создает замыкание, сохраняет объект ячейки для каждого элемента, который должен поддерживать ссылку.

В вашем примере lambda создает замыкание со ссылками на локальные переменные self и model в рамках метода __init__. Если вы где-нибудь ссылаетесь на lambda, вы можете проверить все объекты ячейки его закрытия с помощью атрибута __closure__. В вашем примере это будет выглядеть примерно так:

>>> print(func.__closure__)
(<cell at 0x7f99c16c5138: MyModel object at 0x7f99bbbf0948>, <cell at 0x7f99c16c5168: MyClass object at 0x7f99bbb81390>)

Если вы удалили все другие ссылки на объекты MyModel и MyClass, показанные здесь, те, которые хранятся в ячейках, все равно останутся. Поэтому, когда дело доходит до очистки объекта, вы всегда должны явно отключать все сигналы, связанные с функциями, которые могут образовывать замыкания по соответствующим объектам.


Обратите внимание, что когда дело доходит до соединений с сигналом / слотом, PyQt рассматривает обернутые слоты C ++ и методы экземпляра Python по-разному. Контрольные числа этих типов вызываемых не увеличиваются, когда они связаны с сигналами, тогда как lambdas, определенные функции, частичные объекты и статические методы. Это означает, что если все другие ссылки на последние типы вызываемых удаляются, любые оставшиеся сигнальные соединения будут поддерживать их. Отключение сигналов позволяет при необходимости собирать собранные связанные вызовы.

Единственное исключение из вышеперечисленного - методы класса. PyQt создает специальную оболочку при создании подключений к ним, поэтому, если все другие ссылки на них удаляются, и сигнал испускается, будет генерироваться исключение, например:

TypeError: 'managedbuffer' object is not callable

Вышеприведенное должно применяться к PyQt5 и большинству версий PyQt4 (4.3 и выше).

2
ответ дан ekhumoro 15 August 2018 в 16:53
поделиться
  • 1
    Это подтверждает и разъясняет сохранение ссылки на MyClass и MyModel с помощью лямбда, спасибо! Моя оставшаяся неясность заключается в том, почему сборщик мусора отличается от lambdas, чем для других функциональных объектов. Если бы я хотел, например, создать экземпляр класса и связать один из его методов следующим образом: model.model_changed_signal.connect(ModelListener().handle_signal), экземпляр ModelListener - сбор мусора, а handle_signal никогда не будет вызван. – tjalling 23 December 2017 в 16:47
  • 2
    @tjalling. Мусорное объединение точно такое же для лямбда. Разница полностью обусловлена ​​замыканием, и любая функция any может образовать одну из них. Это закрытие, которое содержит дополнительные ссылки, а не функцию. В примере, приведенном в вашем комментарии, нет закрытия. – ekhumoro 23 December 2017 в 19:01
  • 3
    Но разве нет необходимости также ссылаться на закрытие? Если я удалю последнюю ссылку на лямбда (например, установив ее на None), лямбда и соответствующее закрытие будут собраны в мусор, верно? Почему подключение лямбда к pyqtSignal предотвращает сбор лямбда (и закрытие) от сбора мусора, а привязка связанной функции к сигналу не препятствует тому, чтобы объект (к которому привязана функция) собрали? – tjalling 24 December 2017 в 13:30
  • 4
    @tjalling. Неправильно. Подключите глобальную функцию (с закрытием или без нее) к сигналу, затем удалите глобальную ссылку на функцию - сигнал все равно будет работать. То же самое не так, например, для методов - если экземпляр удален, сигнал будет автоматически отключен. Если pyqt не сохранил ссылку на несвязавшуюся функцию, используемую в качестве слота, сигнал никогда не сможет работать вообще , потому что соединение будет нарушено, как только объект функции выходит из области видимости. – ekhumoro 24 December 2017 в 20:00
  • 5
    @ekhumorao: Точно. Я ожидаю, что лямбда будет немедленно собрана мусором, и поэтому никогда не будет работать вообще . И мне было интересно, является ли причина, по которой он работает , (a) что-то о lambdas / lifetime в Python, с которым я не знаком, или (b ) PyQt обрабатывает lambdas / несвязанные функции иначе, чем связанные функции. Из вашего комментария, я понимаю, что это (b) . Это верно? – tjalling 27 December 2017 в 11:27
Другие вопросы по тегам:

Похожие вопросы: