The problem is more relative to C++ than Python.
The following should be considered:
QApplication is accessed by the entire application using the instance() method since it is a singleton.
When the exit() method is called, it does not eliminate the object just stop processing the events.
So when you create another QApplication without deleting the previous one, the instance is not created and therefore instance() is nullptr:
import sys
from PyQt5.QtWidgets import QApplication, QMessageBox
if __name__ == "__main__":
app = QApplication(sys.argv)
print(f"app: {app}, instance: {QApplication.instance()}")
msg = QMessageBox()
msg.setText("Message Box 1")
msg.show()
app.exit(app.exec())
app = QApplication(sys.argv)
print(f"app: {app}, instance: {QApplication.instance()}")
Output:
app: <PyQt5.QtWidgets.QApplication object at 0x7effbd41ea50>, instance: <PyQt5.QtWidgets.QApplication object at 0x7effbd41ea50>
app: <PyQt5.QtWidgets.QApplication object at 0x7effbd41eb90>, instance: None
So at the time of setting the text with setText() a signal is used that uses the eventloop through the QXApplication using the instance() method that as we see is nullptr generating the segmentation fault.
In the case of using other names for QXApplication the eventloop will access another instance() that will not be None (nullptr)
import sys
from PyQt5.QtWidgets import QApplication, QMessageBox
if __name__ == "__main__":
app1 = QApplication(sys.argv)
print(f"app: {app1}, instance: {QApplication.instance()}")
msg = QMessageBox()
msg.setText("Message Box 1")
msg.show()
app1.exit(app1.exec())
app2 = QApplication(sys.argv)
print(f"app: {app2}, instance: {QApplication.instance()}")
msg = QMessageBox()
msg.setText("Message Box 1")
msg.show()
app2.exit(app2.exec())
Output:
app: <PyQt5.QtWidgets.QApplication object at 0x7f3462720a50>, instance: <PyQt5.QtWidgets.QApplication object at 0x7f3462720a50>
app: <PyQt5.QtWidgets.QApplication object at 0x7f3462720b90>, instance: <PyQt5.QtWidgets.QApplication object at 0x7f3462720b90>
In conclusion if you do not use del then instance() it will be None, however if you use it it will be called the destructor of the object in C++ eliminating the memory returned by instance() and allowing to create a new object.
As @ekhumoro says:
It's the exact order of deletion that really matters. Without del, the
new QApplication is created before the old one is deleted (so the old
instance() doesn't get replaced). But then the app variable is
immediately reassigned, which implictly deletes the old application,
making instance() return None.