Python Forum
[PyQt] Managing variables accross a multiple module GUI
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyQt] Managing variables accross a multiple module GUI
#1
I would like to know what are the best practices to manage variables in a complex application (ie multiple windows/menus/forms etc). I am relatively new to GUI programming so I apologize for any misconception I would have.
My issue is with variables representing data or application-wide settings that are meant to me shared between the different modules

Up to now I have found 2 approaches:
1) the variables are assigned in a common top level scope (mainwindow for ex) and variable values are passed to child widgets when needed.
This seems to be the safest approach as only the relevant variables are passed as argument to the child scope. However the values modified in the child scope must eventually be returned to update the "original" variable in the top level scope. This method looks cumbersome when a large number of variables is involved over multiple scope levels.
-or-
2) the variables are assigned in a separate .py file which is imported into each relevant module. This method is more direct, no passing arguments, no need to return anything since the variables can be directly read/modified from any scope inside the module. I personnaly do not like this approach which looks like an equivalent of global variables since the data can be accessed from anywhere inside the module without explicitly passing arguments.

As I see it, both methods have their drawbacks and i am unsure what whould constitute a "good" approach for a GUI developper. Any thoughts or recommendations?
Reply
#2
First and foremost -- K.I.S.S. It -- aka Keep It Simple and Smart -- keep in mind making something more complex is often not smart as it can cause lots of issues later on.

Yes (2) sounds like another way to implement global variables which are and were almost always a very bad idea. Yes sometimes unavoidable but most of the time not the case just lazy thinking. (1) Sometimes passing a structure containing data works but most often if you find you are passing quite a few bits of information then their is something wrong with the basic design try rethinking things.

Now as for variables in generaly this is greatly dependent on the variables in question but I typically pass just a handle to the child of its parent in most cases where there is something significant going on within the child that might require the parents guidance or assistance. This thus allows direct access of all the shared variables in the child to the parent and vice versa. For again passing specific variables can get rather lengthy and/or cumbersome eventually and eventually this means you need to rethink the design.

Next make sure your variables have the proper scope and that you are not being lazy minded and just creating global variables (or nearly global variables) for nearly everything. I see this a lot in post production code and subsequently have had to clean a lot of that up. Make sure that the variable needs to be persistent but also make sure it needs to be shared. Sometimes restructuring the code can limit the need of passing and/or sharing such variables. For instance maybe instead of passing some variables you got from the database you instead pass a handle to the database class or create another instance of that class locally. Keep in mind keeping a persistent connection to any data source (be it a database or otherwise) is generally not a good idea for many reasons so doing this is quite viable in most cases.

When modularizing your GUI do your best to design it so that each module encapsulates its functionality in a manner that "passing variables" between modules becomes the exception and not the rule.

Okay those are just a few ideas. Again K.I.S.S. It always -- and thoroughly exercise the gray matter to produce quality designs
Reply
#3
Both approach can be useful. I use the second for static variable (ie. project id):

__id__.py

ID = "obsuite"
HELP = ["..."]
__init__.py

try:
    from .__id__ import ID, HELP
except ImportError:
    from __id__ import ID, HELP
And the first approach for common variable across modules/plugins. Like Denni suggested, instead of passing variable I pass self as the module parent. The objects are accessed as pointers, so any change you make is passed upstream.

This is kind of a large project, but still you may have a look to see how it can be implemented:
https://gitlab.com/william.belanger/obsu...er/obsuite
Reply
#4
Thank you both for your answers.

I'm trying to clean up a program made by a colleague and it's a collection of everything you shouldn't do in programming (think global variables everywhere, while loops, redundant code, etc). I've shrunk the code for calculations by a good 1/3, but the UI really needs to be sorted out.
Right now every "important" variable is accessed like a global from just about anywhere in the code. I think referring to the parent might should the trick to simplify variable access between the modules however I'll have to reorganise everything from scratch first.

I'll have a look at Alfalfa's code as soon as I have time, to see how everything fits together and hopefully get some insight on how to reorganise this mess! LOL
Reply
#5
Note one of things I have found with the GUI is that it ought to be Class-ified a lot which is to say building sub-classes to handle various sub-elements is a lot cleaner and easier to maintain than having all the functionality within a single Class which seems to be how PyQt was designed -- so inheritance and re-classing things is often a very solid answer to making the code easier to read/maintain as well as necessary in order to do certain things
Reply
#6
Yes that's what I'm trying to do with the program I'm cleaning up, since nearly everything was dumped in the main script and for the most part, in the mainwindow class. I'm trying to break down the program into what does the science, what does the IO, and then the GUI into basic functional blocs that can function independently (easier to test that way, isn't it?).
The challenge for me now is to figure out how to best structure the program from the variables point of view so each widget/class can do its thing.
Reply
#7
to share variables between modules, i have learned here, is to make yet another module (that all the other modules can see a reference to) that has a class. this can just be an empty class and you can put stuff in its attributes.
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#8
I already use my "constants" and a few variables that affect the program as a whole this way. However I have a problem using this method for other than these two cases because you're basically creating global variables. Is this really what programmers recommend?
Reply
#9
they are "limited global" because you have to access that class and the attribute form avoids a collision with common simple variable names. i actually added this form to my debug helper function that dumps a variable given its name (it "inspects" the caller's namespaces to see where it is from the caller's perspective).
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#10
NO -- if at all possible do not use global variables or even semi-global variables in most (not all) cases these types of variables are completely unnecessary and always very dangerous and a nightmare if a bug develops because of one. Basically global and semi-global variables are due to lazy minded coding -- a properly designed program should never need these kinds of variables especially with python as your base language. Keep in mind a Class should be autonomous never dependent upon any outside variables and your program should be class-ified thus meaning all variables are contained within their appropriate class. Again I know your pain, having had to do this numerous times myself but the best method I could find is start mapping these variables out as well as the code structure and then figure out where the break-down has occurred and address that point(s) eventually you should be able to eliminate nearly all globals and semi-global variables and have your variables all properly contained. Good luck and above all things just have fun its grand puzzle you are trying to solve one that has numerous pieces that are interchangeable but only the right piece is going to make the picture viewable.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Question [Tkinter] Defining a self made module's function to interact with the main .py variables? Gilush 9 4,346 Jun-08-2020, 09:08 AM
Last Post: Gilush

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020