Avoid circular import when accessing instance value from main.py
Question:
I´m new to Python and programming in general. So maybe there is an easy solution for more experienced programmers.
I already read a lot of question regarding circular imports, but unfortunately there was nothing there that I can apply to my situation if I dont want to move all the code in one file.
I created an userinterface with pyqt (qt creator) and converted the mainwindow.ui to mainwindow.py.
My plan is to split the code into 3 modules. A main module to start the application, an ui module with the class of the main window and a buttons module with classes for the buttons.
My problem is that the functions within the button classes should change a label value of the main window instance. I learned to create the main window instance in the main module. As a result of this I need to import the instance from the main module into the buttons module to change the intended value and that leads to an circular import.
How do I have to organize/structure my code to avoid this?
Here is a short and simplified example for better understanding:
main.py
import sys
from qtpy import QtWidgets
from ui import MainWindow
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
ui.py
from qtpy import QtWidgets
from userinterface.mainwindow import Ui_MainWindow
import buttons
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.button_0 = buttons.NumberButton(0)
self.button_1 = buttons.NumberButton(1)
self.ui.btn_0.clicked.connect(self.button_0.button_clicked)
self.ui.btn_1.clicked.connect(self.button_1.button_clicked)
buttons.py
from main import window
class NumberButton:
def __init__(self, number):
self.number = str(number)
def button_clicked(self):
window.ui.lb_result.setText(self.number)
Answers:
If you only import the module python should automatically avoid circular imports. So do import ui
and import buttons
Your design problem is that your NumberButton
class calls one specific window instance. Your have to let your buttons know to which window they belong. Try the following: remove the import statement from buttons.py and add a new parameter window
to the __init__
method:
class NumberButton:
def __init__(self, window, number):
self.window = window
self.number = str(number)
def button_clicked(self):
self.window.ui.lb_result.setText(self.number)
Then instantiate in NumberButton
like:
...
self.button_0 = buttons.NumberButton(self, 0)
...
I´m new to Python and programming in general. So maybe there is an easy solution for more experienced programmers.
I already read a lot of question regarding circular imports, but unfortunately there was nothing there that I can apply to my situation if I dont want to move all the code in one file.
I created an userinterface with pyqt (qt creator) and converted the mainwindow.ui to mainwindow.py.
My plan is to split the code into 3 modules. A main module to start the application, an ui module with the class of the main window and a buttons module with classes for the buttons.
My problem is that the functions within the button classes should change a label value of the main window instance. I learned to create the main window instance in the main module. As a result of this I need to import the instance from the main module into the buttons module to change the intended value and that leads to an circular import.
How do I have to organize/structure my code to avoid this?
Here is a short and simplified example for better understanding:
main.py
import sys
from qtpy import QtWidgets
from ui import MainWindow
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
ui.py
from qtpy import QtWidgets
from userinterface.mainwindow import Ui_MainWindow
import buttons
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.button_0 = buttons.NumberButton(0)
self.button_1 = buttons.NumberButton(1)
self.ui.btn_0.clicked.connect(self.button_0.button_clicked)
self.ui.btn_1.clicked.connect(self.button_1.button_clicked)
buttons.py
from main import window
class NumberButton:
def __init__(self, number):
self.number = str(number)
def button_clicked(self):
window.ui.lb_result.setText(self.number)
If you only import the module python should automatically avoid circular imports. So do import ui
and import buttons
Your design problem is that your NumberButton
class calls one specific window instance. Your have to let your buttons know to which window they belong. Try the following: remove the import statement from buttons.py and add a new parameter window
to the __init__
method:
class NumberButton:
def __init__(self, window, number):
self.window = window
self.number = str(number)
def button_clicked(self):
self.window.ui.lb_result.setText(self.number)
Then instantiate in NumberButton
like:
...
self.button_0 = buttons.NumberButton(self, 0)
...