Memory_profiler While Using Lambda Expression To Connect Slots
Solution 1:
The problem pointed out in this post does not have to do with PyQt5 but with the lambda functions since, like any function, it creates a scope and stores memory, to test what the OP points out I have created the following example:
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.counter = 0
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.on_timeout)
self.timer.start(1000)
self.button = QtWidgets.QPushButton("Press me")
self.setCentralWidget(self.button)
@QtCore.pyqtSlot()
def on_timeout(self):
self.counter += 1
if self.counter % 2 == 0:
self.connect()
else:
self.disconnect()
def connect(self):
self.button.setText("Connected")
self.button.clicked.connect(lambda checked: None)
# or
# self.button.clicked.connect(lambda checked, v=list(range(100000)): None)
def disconnect(self):
self.button.setText("Disconnected")
self.button.disconnect()
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
self.button.clicked.connect(lambda checked: None)
self.button.clicked.connect(lambda checked, v=list(range(100000)): None)
As observed at the time of connection and disconnection, the memory consumed increases since the lambda maintains the information of v=list(range(100000))
.
But in your code the closure stores only the variable "j" which is minimum:
getattr(self, i).clicked.connect(lambda pippo, j=i: self.printo(j))
To see how this variable affects I am going to eliminate the unnecessary code for the test (hangman005.py, etc) in addition to offering alternatives:
- without connect:
class MainMenu(QtWidgets.QMainWindow):
def __init__(self):
super(MainMenu, self).__init__()
uic.loadUi("main_window2.ui", self)
self.hangman()
def hangman(self):
letters = "ABCDEFGHIJKLMNOPQRSTYVWXXYZ"
for i in letters:
pass
def printo(self, i):
print("oooooooooooooooooooooo :", i)
- with lambda:
class MainMenu(QtWidgets.QMainWindow):
def __init__(self):
super(MainMenu, self).__init__()
uic.loadUi("main_window2.ui", self)
self.hangman()
def hangman(self):
letters = "ABCDEFGHIJKLMNOPQRSTYVWXXYZ"
for i in letters:
getattr(self, i).clicked.connect(lambda pippo, j=i: self.printo(j))
def printo(self, i):
print("oooooooooooooooooooooo :", i)
- with functools.partial
class MainMenu(QtWidgets.QMainWindow):
def __init__(self):
super(MainMenu, self).__init__()
uic.loadUi("main_window2.ui", self)
self.hangman()
def hangman(self):
letters = "ABCDEFGHIJKLMNOPQRSTYVWXXYZ"
for i in letters:
getattr(self, i).clicked.connect(partial(self.printo, i))
def printo(self, i):
print("oooooooooooooooooooooo :", i)
- once connect
class MainMenu(QtWidgets.QMainWindow):
def __init__(self):
super(MainMenu, self).__init__()
uic.loadUi("main_window2.ui", self)
self.hangman()
def hangman(self):
letters = "ABCDEFGHIJKLMNOPQRSTYVWXXYZ"
for i in letters:
getattr(self, i).setProperty("i", i)
getattr(self, i).clicked.connect(self.printo)
def printo(self):
i = self.sender().property("i")
print("oooooooooooooooooooooo :", i)
As we can see there is no significant difference between all the methods so in your case there is no memory leak or rather it is very small.
In conclusion: Every time you create a lambda method it has a closure (j = i
in your case) so the OP recommends taking that into account, for example in your case len(letters) * size_of(i)
are consumed which at Being small letters
and i
makes it negligible, but if you otherwise store a heavier object unnecessarily then it will cause problems
Post a Comment for "Memory_profiler While Using Lambda Expression To Connect Slots"