0

So this block of code tells me build_master_config_dictionary() is not defined. I know if I declare this statement at the bottom of code it will work, but I would like to contain the list of constants at the top of the python script for readability. This script will eventually contain a bunch of similar constants that will be used by other scripts in my program.

Is there a better way of doing this?

import json
from pathlib import Path
from glob import glob

JSON_CONFIG_DIR = "data\JSON\Configs"
MASTER_CONFIG_SITE_DICT = build_master_config_dictionary()

 
# Builds a python dictionary that contains config info by Site-> Unit Name-> Config details
def build_master_config_dictionary():
    master_json_file_dict = {}
    for relative_fp in glob(JSON_CONFIG_DIR + '\*.json'):
        try:
            with open(relative_fp) as f:
                filename = Path(relative_fp).stem
                master_json_file_dict[filename] = json.load(f)

        except Exception as e:
            print(f'build_master_config_dictionary:  unable to load in json file - {relative_fp}')

# MASTER_CONFIG_SITE_DICT = build_master_config_dictionary()
martineau
  • 119,623
  • 25
  • 170
  • 301
Richard
  • 63
  • 1
  • 7
  • You want to use a main function, which is the standard in Python programs. See https://realpython.com/python-main-function/ – James Oct 20 '21 at 21:40
  • This script will be used by other scripts where the main function is located for the app. The main function in the script would never be called – Richard Oct 20 '21 at 21:43
  • It’s not a constant, like 2393 or “hello” would be. You can’t assign it before it’s defined. – DisappointedByUnaccountableMod Oct 20 '21 at 21:55
  • 2
    Python scripts are executed top down. You can't invoke a function until its definition has been executed. You could move the functions into a separate module, and have all the constants in a module by themselves, which imports the module that contains the functions. – dirck Oct 20 '21 at 21:58
  • 1
    It's not really a constant to begin with, as it's computed from configuration and thus could be subject to change. Anyone looking at your code for the value would gain very little from finding it at the top - good code needs little documentation, but this is one of those situations where documenting what people can expect to find is a better solution than moving code around. If the reading of configuration is something you'd rather just get out of the way altogether, stick it in separate module and import the value. – Grismar Oct 20 '21 at 23:27
  • 2
    The best way to handle a bunch of constants that are going to be used in multiple scripts is to put them all their own module and `import` it at the beginning of any scripts that need them. See [How do I share global variables across modules?](https://docs.python.org/3/faq/programming.html?highlight=shared#how-do-i-share-global-variables-across-modules) in the documentation. – martineau Oct 20 '21 at 23:28
  • Is this module already part of a larger package? – tdelaney Oct 20 '21 at 23:38

1 Answers1

1

One option would be to put your function definitions in a separate file (myfunctions.py), and have the action take place in a file called main.py

myfunctions.py

import json
from pathlib import Path
from glob import glob  
 
# Builds a python dictionary that contains config info by Site-> Unit Name-> Config details
def build_master_config_dictionary():
    master_json_file_dict = {}
    for relative_fp in glob(JSON_CONFIG_DIR + '\*.json'):
        try:
            with open(relative_fp) as f:
                filename = Path(relative_fp).stem
                master_json_file_dict[filename] = json.load(f)

        except Exception as e:
            print(f'build_master_config_dictionary:  unable to load in json file - {relative_fp}')

main.py

from myfunctions import build_master_config_dictionary

JSON_CONFIG_DIR = "data\JSON\Configs"
MASTER_CONFIG_SITE_DICT = build_master_config_dictionary()

Now your main.py file maintains readibility and it is still easy to find where your functions come from.

alex_danielssen
  • 1,839
  • 1
  • 8
  • 19
  • What if the MASTER_CONFIG_SITE_DICT variable is used in multiple modules in my app. I don't want to have to rebuild the dictionary each time by calling the function, i want to build it once and return the result - maybe I need to add a better method but I presume this isn't pythonic and there probably is a better way – Richard Oct 21 '21 at 01:32
  • 1
    well, you could write your functions so that they all accept a config parameter `def f(config, ...)` and then use the specific MASTER_CONFIG_SITE_DICT when you call the top-level functions in `main.py`. – alex_danielssen Oct 21 '21 at 13:41
  • 2
    @Richard: There are different ways of only computing something the first time it's needed and caching its value. One of them: [What is a lazy property?](https://stackoverflow.com/questions/24704147/what-is-a-lazy-property). – martineau Oct 21 '21 at 20:26