pythonpython-2.7nameerrorglobal-scope

KeyError: global not accessible through imported class


I am trying to calculate the number of elements in a chemical equation. The debugger that I have created somehow doesn't have access to the globals within my program. Specifically, I am trying to access carrots but left is not being added to the stack. Any ideas?

Debug.py

class Debugger(object):
    def __init__(self,objs):
        assert type(objs)==list, 'Not a list of strings'
        self.objs = objs
    def __repr__(self):
        return '<class Debugger>'
    def show(self):
        for o in self.objs:
            print o,globals()[o] #EDIT

Chemical_Balancer.py

from Debug import Debugger

def directions():
    print 'Welcome to the chem Balancer.'
    print 'Use the following example to guide your work:'
    global left #LEFT IS GLOBAL
    left = 'B^6 + C^2 + B^3 + C^3 + H^9 + O^4 + Na^1'
    print left
    print "#Please note to use a 'hat' when entering all elements"
    print '#use only one letter elements for now'
# left = raw_input('enter formula:')  #enter formula to count
directions()

chem_stats = {}
chem_names = []
chem_names = []
chem_indy = []

for c in range(len(left)):
    if left[c].isalpha() and left[c].isupper():
        chars = ''
        if left[c+1].islower():
            chars += left[c]+left[c+1]
        else:
            chars += left[c]
        #print chars
        chem_indy.append(c)
        chem_names.append(chars)

carrots = [x for x in range(len(left)) if left[x]=='^']

debug = Debugger(['carrots','chem_names','chem_indy','chem_stats']) # WITHOUT LEFT
debug.show()

Error message:

Traceback (most recent call last):
  File "C:\Python27\#Files\repair\Chemical_Balancer.py", line 38, in <module>
    debug.show()
  File "C:\Python27\lib\site-packages\Debug.py", line 12, in show
    print o,globals()[o]
  File "<string>", line 1, in <module>
KeyError: 'carrots'

Solution

  • About the specific error on the left variable:

    when you say a variable is global, python knows it has to look it up in the global namespace when its name is used. But in the code left hasn't been assigned in such namespace.

    As you can see, left is commented out

    #left = raw_input('enter formula:')  #enter formula to count
    

    Uncomment it by removing the # at the beginning of the line, so the line inside the directions function

    global left
    

    can find it and the instructions that follow can work.

    About the implementation: one solution to allow the debugger to know where to look for the variables, i.e. in which module, can be to provide the name of the module to it when it is created. Then the debugger object can reach the global variables of the module that created it via sys.modules[module_name].__dict__

    debugger.py

    import sys
    class Debugger(object):
        def __init__(self, module_name, objs):
            assert type(objs)==list,'Not a list of strings'
            self.objs = objs
            self.module_name = module_name
        def __repr__(self):
            return '<class Debugger>'
        def show(self):
            for o in self.objs:
                print o, sys.modules[self.module_name].__dict__[o]
    

    chemical_balancer.py

    import debugger as deb
    a = 1
    b = 2
    d = deb.Debugger(__name__, ['a', 'b'])
    print(d.objs)
    d.show()
    a = 10
    b = 20
    d.show()
    

    which produces

    ['a', 'b']
    a 1
    b 2
    a 10
    b 20
    

    As you can see, the debugger prints the current value of the variables each time its show method is called

    I have found this SO Q&A informative and helpful.