Search code examples
pythonglobal-scope

python global variable scope confusion. What are these variables not accessible?


I see there are a few of these questions on here, but I haven't found one that quit matches what I'm after.

I have a common file, lets call it tools.py. In this file I have a host of path definitions to use and an init_paths function to set some key paths based on command line arguments:

def init_paths(args):
    global tools_dir, tools_src, tools_bin

    if args.tools_set:
        tools_dir = os.path.realpath(os.path.join(args.tools_set,"tools"))
    else:
        tools_dir = os.path.join(BAR_PATH, "tools")

FOO_PATH = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), ".."))
BAR_PATH = os.path.join(FOO_PATH, "foobar")
tools_dir = none
tools_src = none
tools_bin = none

etc...

I have a main file, lets call it main.py where I want to use these.

if __name__ == "__main__":
    args = parseArgs()
    from tools import init_paths
    init_paths(args)
    doStuffFunction(args.one, args.two, args.three)

I have left out the meat and potatoes to be sure, but I believe this should be enough to illustrate my global scope problem. when I run this: python main.py --tools-set=/path/to/tools, I am expecting the call to init_paths, to set up some key paths I wish to use later in the doStuffFunction().

def doStuffFunction():
    searchPath = os.path.join(tools_dir, "folder")

this fails: AttributeError: 'NoneType' object has no attribute endswith

pretty sure this is because it is not getting set. but why?

EDIT

main.py

#!/usr/bin/env python
import sys
import os
import argparse
import glob
from tools import *


def parseArgs():
    parser = argparse.ArgumentParser(description="parse my args")
    parser.add_argument("--toolchain-root", type=str,default=None,help='specify toolchain directory')
    args = parser.parse_args()

    return args


def doStuffFunction():
    output = 'output'
    if not os.path.isdir(output):
        os.makedirs(output)
    gimmySugar(output)

def gimmySugar(output):
    fileList = []
    linkBook= {}

    searchPath = os.path.join(tools_BIN_ROOT,'gcc-4.8.5')
    for root, dirs, files in os.walk(searchPath):
        for libFile in glob.glob(root+'/*.so*'):
            fileList.append(libFile)
            if os.path.islink(libFile):
                linksWith = os.readlink(libFile)
                linkBook[libFile] = linksWith

if __name__ == "__main__":
    # script was called directly from the command line
    args = parseArgs()
    from tools import init_settings
    init_settings(args)
    doStuffFunction()

tools.py

import os

def init_settings(args):
    global tools_DIR, tools_SRC_ROOT, tools_OBJ_ROOT, tools_BIN_ROOT
    if args.toolchain_root:
        tools_DIR = os.path.realpath(os.path.join(args.toolchain_root, "toolchain"))
    else:
        tools_DIR = os.path.join(USER_DIR, "")
    tools_SRC_ROOT = os.path.join(tools_DIR, "src")
    tools_OBJ_ROOT = os.path.join(tools_DIR, "obj")
    tools_BIN_ROOT = os.path.join(tools_DIR, "bin")


ROOT_PATH = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), ".."))
OUTPUT_PATH = os.path.join(ROOT_PATH, "outputs")
BUILD_PATH = os.path.join(OUTPUT_PATH, "build")
USER_DIR = "/usr/lib64/"
tools_DIR = None
tools_SRC_ROOT = None
tools_OBJ_ROOT = None
tools_BIN_ROOT = None

Solution

  • #This line will failed
    searchPath = os.path.join(tools_BIN_ROOT,'gcc-4.8.5')
    

    The scope of global variables is module level, tools_BIN_ROOT will not be shared without passing across modules.

    The variable tools_BIN_ROOT is global variable ONLY in tools.py. Insteadly, main.py do not contain any global variable in tools.py.

    For inspecting this, you can use print(globals()) in both files.


    Do not use global variable if possible.

    This is a simple workaround.

    (I strongly recommend you to refactor your code by config or OOP)

    tools.py

    def get_tools_BIN_ROOT():
        return tools_BIN_ROOT
    

    os.py

    from tools import get_tools_BIN_ROOT
    searchPath = os.path.join(get_tools_BIN_ROOT(),'gcc-4.8.5')