0

So I have read that the way to share globals across files is to create a module which holds globals and import this in all python files needing to access the global. However it doesn't seem to work as expected for me (Python 3.6+)

Simple directory structure:

run.py
mypack/
   -- globals.py
   -- stuff.py
   -- __init__.py

I have a global var in globals.py which I need to modify in main file (run.py) and finally print out while exiting the program. It does not seem to work:

__init__.py:

from .stuff import *

globals.py:

test = 'FAIL'

stuff.py:

import atexit
from .globals import test

def cya():
    print ("EXIT: test = " + test)

atexit.register(cya)

def hi():
    print('HI')

run.py:

import mypack
import mypack.globals as globals

mypack.hi()
globals.test = 'PASS'

print ("MAIN: test = " + globals.test)

Output on script execution:

HI
MAIN: test = PASS
EXIT: test = FAIL

Clearly the exit routine (cya) did not show the correct value of global value that was modified in run.py. Not sure what I am doing wrong.

backstreetrover
  • 203
  • 1
  • 11

3 Answers3

0

the python documentation might help you on this one.

https://docs.python.org/3/faq/programming.html#how-do-i-share-global-variables-across-modules

Brody Critchlow
  • 45
  • 3
  • 21
  • that is what I got the idea of using a module to store globals. However when implementing it, it doesnt work as expected. – backstreetrover Sep 10 '21 at 17:30
  • try `stuff.test = "whatever"`? – Brody Critchlow Sep 10 '21 at 17:30
  • `mypack.stuff.test = 'whatever'` works but it defeats the purpose. The aim is not to modify module local variables. It is to only modify the variables in globals module and have that reflect throughout. – backstreetrover Sep 10 '21 at 17:41
  • I guess I dont understand your question then? It looks like you are trying to modify the data of the variable in a different file. – Brody Critchlow Sep 10 '21 at 17:42
  • my real use case is to pass the logger and log_count variables across modules (which would not be strings, but other objects). But I just framed a simpler question here to explain the issue. I will have likely several modules created. Each one will need to access the global and potentially modify it. Having each module access the local variable from every other module is not feasible. I want to import a set of globals, and ensure that modification to them is reflected in every other module immediately. – backstreetrover Sep 10 '21 at 17:45
0

Issue was: at each import all variables will be reinitialized thier values. Use singleton object:

universal.py

import logging


class GlobVars:

    _instances = {}
    
    def __new__(cls, logger, counter_start=0):
        if cls not in cls._instances:
            print("Creating Instance")
            cls._instances[cls] = super(GlobVars, cls).__new__(cls)
        return cls._instances[cls]

    def __init__(self, logger, counter_start=0):
        self.logger = logger
        self.counter = counter_start

glob_vars = GlobVars(logger=logging.getLogger("basic_logger"))

run.py

from universal import glob_vars

glob_vars.logger.info("One logger rulles them all")
Peter Trcka
  • 1,279
  • 1
  • 16
  • 21
  • This is **completely wrong** – juanpa.arrivillaga Sep 10 '21 at 18:04
  • @juanpa.arrivillaga can you explain why this is wrong. adding it to a class worked for me. – backstreetrover Sep 10 '21 at 18:06
  • Can you be more specific? This type of comments don't help. – Peter Trcka Sep 10 '21 at 18:07
  • Your claim that a module is re-initialized. Totally wrong. And easily verifiable as wrong. – juanpa.arrivillaga Sep 10 '21 at 18:08
  • Not module, but variables from this module. I think I understand your concern. You meant that module is imported only once during whole program? – Peter Trcka Sep 10 '21 at 18:11
  • As an aside, your `GlobVars` class is not a singleton.... not sure what the point of overriding `__new__` was here... – juanpa.arrivillaga Sep 10 '21 at 18:11
  • 1
    @PeterTrcka **totally wrong**. They absolutely do not get re-initialized. And yes, modules are cached once they are imported. The problem with the OP is that they used `from .globals import test`, this creates a *new global variable* in the module doing that. Assignments to `global.test` won't affect *that variable*. See the linked duplicate – juanpa.arrivillaga Sep 10 '21 at 18:12
  • A module already is a singleton object, you just have to *use that object*. – juanpa.arrivillaga Sep 10 '21 at 18:17
  • @juanpa.arrivillaga you are right. That definition was not Singleton. So you meant that there is no need to implement singleton pattern just using the object will work ? – Peter Trcka Sep 10 '21 at 18:19
  • @PeterTrcka just using *the module object yes*. In general, the singleton pattern is never really useful. certainly not in Python. In this case, the simples solution is to change `from .globals import test` to `import .globals` and then use `globals.test` – juanpa.arrivillaga Sep 10 '21 at 18:23
  • @juanpa.arrivillaga thanks for explanation. I have never thought about it this way: if modules are cached, and you import object, you are still using the same object, and if any other module change attribute value, this change will be reflected every where, because it is still that one object. Am I correct? – Peter Trcka Sep 10 '21 at 18:29
  • @PeterTrcka yep, that is correct – juanpa.arrivillaga Sep 10 '21 at 18:34
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/236984/discussion-between-peter-trcka-and-juanpa-arrivillaga). – Peter Trcka Sep 10 '21 at 18:49
0

Thanks to @PeterTrcka for pointing out the issue. Also thanks to @buran for indicating globals is a bad name for module since its inbuilt function. Here is the working solution:

directory structure:

run.py
mypack/
   -- universal.py
   -- stuff.py
   -- __init__.py

__init__.py:

from .stuff import *

universal.py:

class GlobalVars:
  test = 'FAIL'

stuff.py:

import atexit
from .universal import GlobalVars

def cya():
    print ("EXIT: test = " + GlobalVars.test)

atexit.register(cya)

def hi():
    print('HI')

run.py:

import mypack
from mypack.universal import GlobalVars

mypack.hi()
GlobalVars.test = 'PASS'

print ("MAIN: test = " + GlobalVars.test)

Output on script execution:

HI
MAIN: test = PASS
EXIT: test = PASS
backstreetrover
  • 203
  • 1
  • 11