2

So, what i'm trying to do is use the python interpreter as sort of a CLI for my server side python app. However, I'm getting a behavior i didn't expect in the loading of python modules.

I have two python files and a cache file:

Main.py
Config.py
Cache.json

So what happens is that when Main is imported and ran, the main() function imports Configs and then calls a function to initialize Config. When initialized Config loads some global variables from Cache.json depending on the environment i'm running in. Here's a simplified example of the .py 's.

#Main.py
import Config

def main():
    """Initialize Python Application"""
    Config.init()


if __name__ == "__main__":
    main()

#Config.py
import os
import json

Default_MSSQLPassword = ""
Default_MSSQLUser = ""
Default_OdbccDriver = ""
MDGSQLP01 = ""


def init():
    """docstring"""

    with open("Cache.json", "r") as f:
        dtGlobalConstants = json.load(f)

    Default_MSSQLPassword = dtGlobalConstants["Default_MSSQLPassword"]
    Default_MSSQLUser = dtGlobalConstants["Default_MSSQLUser"]
    Default_OdbccDriver = dtGlobalConstants["Default_OdbccDriver"]
    MDGSQLP01 = dtGlobalConstants["MDGSQLP01"]

Now theoretically if I call the below in the python interpreter:

>>>from Main import main
>>>main()

Config should be imported by main(), persist, and I should be able to print the Cached value of Default_OdbccDriver that was loaded form Cache.json. But instead I get this:

>>>Config.Default_OdbccDriver
>>>''

So clearly Main is importing Config.py, because otherwise i'd get an error when calling property .Default_OdbccDriver . However, even though the value of Default_OdbccDriver is supposed to be "global" (according to python's odd definition of the word) it's value should be static and persist in the import cache.

Anyone know what's going on or how to work around it? In the end, I want main() to initialize some values and expose some methods for working with my app, but this isn't a great start...

2 Answers 2

4

You should declare your variables as global in the init function, otherwise you are just setting some local variables of the function shadowing the global ones:

def init():
    """docstring"""
    global Default_MSSQLPassword
    global Default_MSSQLUser
    global Default_OdbccDriver
    global MDGSQLP01

    with open("Cache.json", "r") as f:
        dtGlobalConstants = json.load(f)

    Default_MSSQLPassword = dtGlobalConstants["Default_MSSQLPassword"]
    Default_MSSQLUser = dtGlobalConstants["Default_MSSQLUser"]
    Default_OdbccDriver = dtGlobalConstants["Default_OdbccDriver"]
    MDGSQLP01 = dtGlobalConstants["MDGSQLP01"] 

As you say in the comment, when importing into the session that variables are bind to Main.Config.your_var_name for solving this should be enough to declare them as global also in the module:

#Config.py
import os
import json

global Default_MSSQLPassword
global Default_MSSQLUser
global Default_OdbccDriver
global MDGSQLP01

Default_MSSQLPassword = ""
Default_MSSQLUser = ""
Default_OdbccDriver = ""
MDGSQLP01 = ""


def init():
    """docstring"""
    global Default_MSSQLPassword
    global Default_MSSQLUser
    global Default_OdbccDriver
    ...
Sign up to request clarification or add additional context in comments.

4 Comments

I got some interesting results with this. Oddly... if I call the function from the interactive window using: from Main import main and run main() i still get a blank string. However, if I run the script from the interactive window like exec(open("Main.py").read()) then the value of my Config variables return as expected. Any idea why this happens?
@JamieMarshall yes, when importing into the session that variables are not really global they are bind to Main.Config.your_var_name
Wow, what a gotchya! I couldn't even get Main.Config.var using from Main import main I had to go back and Import Main, which is odd because the Main object already exists and has the value of the variables. So weird. So is this really an access inconsistency between import and exe, or is there actually two separate instances of Config being created?
@JamieMarshall, in exe the main scope is the Main file one, in the interactive session is the session itself, that is why importing main it didnt work as spected
0

It looks like you are using config as if it were a class, but not defining it as one. if you want a config object, you can define it instead like this:

#Config.py
import os
import json

class Config:

    def __init__(self):
        """docstring"""

    dtGlobalConstants = {}

    with open("Cache.json", "r") as f:
        dtGlobalConstants = json.load(f)

    Default_MSSQLPassword = dtGlobalConstants.get("Default_MSSQLPassword", "")
    Default_MSSQLUser = dtGlobalConstants.get("Default_MSSQLUser", "")
    Default_OdbccDriver = dtGlobalConstants.get("Default_OdbccDriver", "")
    MDGSQLP01 = dtGlobalConstants.get("MDGSQLP01", "")

Now, when you first instantiate a config object, like config = Config(), the config object will have all those variables.

Note also that the dict.get() function will set your variables to "" if it can't find them in that dict

If you use classes instead, you can avoid using global variables, and could even update the config to return a database object functionally, by writing a get_db_object function, so that you can just use config.get_db_object() to create your db object

4 Comments

I don't believe this correct. What I really need are variables that are global and static, but Python's definition of those two concepts is very unconventional. Since Import creates a static object of the module you target it may be the closest thing to a global static variable. As far as I've read through the python docs, I can't guarantee a static value in a class as it is imported in various other modules or packages. I'm unable to locate it now, but i'm sure I took the method i'm using directly from the Python 3.6 docs. Also, objects are by definition non-static.
I guess it depends on what you're going to be doing with these variables. If it's to create a database connection object in your other modules, you don't necessarily need to save these values as global variables, you can create a class like this that instead just returns the database object. These values will be 'static' in the sense that they won't be changed by your code ever, especially if they are only used by this class to create a DB object, whereas the way you are attempting to use them in the python shell can be altered, so could be considered not static
Also just my humble opinion though, I personally prefer more objects and classes in my code
I mean I could be wrong, early days. Just to clarify I mean static as in variables that have only one instance and will contain the same value at a given time no matter where they are called from. The ability to be altered is very much a good thing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.