12

when reading python documentation and various mailing lists I always read what looks a little bit like a dogma. Global variables should be avoided like hell, they are poor design ... OK, why not ? But there are some real lifes situation where I do not how to avoid such a pattern.

Say that I have a GUI from which several files can be loaded from the main menu. The file objects corresponding to the loaded files may be used througout all the GUI (e.g. an image viewer that will display an image and on which various actions can be performed on via different dialogs/plugins).

Is there something really wrong with building the following design:

  • Menu.py --> the file will be loaded from here
  • Main.py --> the loaded file objects can be used here
  • Dialog1.py --> or here
  • Dialog2.py --> or there
  • Dialog3.py --> or there
  • ...
  • Globals.py

where Globals.py will store a dictionary whose key are the name of the loaded files and the value the corresponding file objects. Then, from there, the various part of the code that needs those data would access it via weak references.

Sorry if my question looks (or is) stupid, but do you see any elegant or global-free alternatives ? One way would be to encapsulate the loaded data dictionary in the main application class of Main.py by considering it as the central access part of the GUI. However, that would also bring some complications as this class should be easily accessible from all the dialogs that needs the data even if they are necesseraly direct children of it.

thank a lot for your help

jamylak
  • 128,818
  • 30
  • 231
  • 230
Eurydice
  • 8,001
  • 4
  • 24
  • 37
  • 1
    global variables are not evil. What is evil is using it as a mutable variable. Global variables should remain static and "immutable" whenever possible. If you have to change the dictionary content in globals.py, no good. Other than that, for reading is okay. – CppLearner Apr 15 '13 at 08:48
  • 1
    yes, global "constants" are ok, global "variables" should be avoided. – monkut Apr 15 '13 at 08:50
  • 1
    OK, I get what both of you mean but I still do not see a valid python alternative to the design I proposed in which the loaded data dictionary may evolve through the time (new loaded files, deleted files) – Eurydice Apr 15 '13 at 08:53

2 Answers2

12

Global variables should be avoided because they inhibit code reuse. Multiple widgets/applications can nicely live within the same main loop. This allows you to abstract what you now think of as a single GUI into a library that creates such GUI on request, so that (for instance) a single launcher can launch multiple top-level GUIs sharing the same process.

If you use global variables, this is impossible because multiple GUI instances will trump each other's state.

The alternative to global variables is to associate the needed attributes with a top-level widget, and to create sub-widgets that point to the same top-level widgets. Then, for example, a menu action will use its top-level widget to reach the currently opened file in order to operate on it.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • I will agree on the static member variable/attribute (but not necessarily as per-instance attributes if again just for constant, reading purpose). But depending on requirement, having some constants is not so bad. Just make sure they understand what Python can do and cannot do :p – CppLearner Apr 15 '13 at 08:53
  • If I get you right, such a design would be like a kind of tree where the loaded data dictionary would be stored as an attribute of the root top-level widget. Then all widgets of the application could access it via a call to a "topLevelParent" method. – Eurydice Apr 15 '13 at 08:59
  • You could have a `MainModel` that would store the the file names and the top level data. With QT you would have the main window, and it would store the file names and top level data. The events for opening and writing files are usually handled in the top level objects, the lower level objects don't need to know the file names. – Eike Apr 15 '13 at 09:37
  • @Eike GTK allows the same, and this was the architecture I was describing. That way you automatically get the same level of convenience as with global variables, but without the drawbacks. The point of my answer was to clearly explain the drawbacks, which literature often fails to (convincingly) do, which frustrated the OP. – user4815162342 Apr 15 '13 at 10:34
  • @user4815162342 Yes, indeed. My comment was meant as an answer for Pellegrini Eric's previous comment. – Eike Apr 15 '13 at 11:25
-2

I would manage global data by encapsulating the data in one ore more classes and implement the borg pattern for these classes. See Why is the Borg pattern better than the Singleton pattern in Python

Community
  • 1
  • 1
rocksportrocker
  • 7,251
  • 2
  • 31
  • 48
  • 1
    Please don't advertise the Borg pattern. The whole point of singleton is that you have a **single** instance, thus saving memory and ensuring identical behavior. If it is really necessary to have different instances in different subclasses, there are ways to do that without compromising the basic Singleton requirement to have one instance per class. – user4815162342 Apr 15 '13 at 10:37
  • 3
    Neither the Borg nor the Singleton pattern don't alleviate the main problem of global variables, which is that you have a single global state. In fact, the singleton pattern is simply a nice OO-style interface to a shared global state, which is exactly what the literature is telling (without properly explaining why) the OP to avoid. – user4815162342 Apr 15 '13 at 10:39
  • 1
    I prefer a practical approach: global variables aka singleton aka borg pattern are only dangerous if the code writes and reads from them. A global logger (all clients write) is not dangerous as well as a pool for data base connections (all clients read). It is fine if developers follow books but should not forget the backgound. – rocksportrocker Aug 01 '16 at 18:37
  • @user4815162342 the memory point depends on the number of instances of the borg, if you have thousands of them I assume something else in your design is broken. I do not see why instances of a "borg class" should not show identical behaviour, the shared internal state is the heart of the borg pattern. – rocksportrocker Aug 01 '16 at 18:39