Changing behaviour of namespaces

Mikael Olofsson mikael at isy.liu.se
Thu Sep 21 13:37:35 CEST 2006


Hi!

This is in Python 2.3.4 under WinXP.

I have a situation where I think changing the behaviour of a namespace 
would be very nice. The goal is to be able to run a python file from 
another in a separate namespace in such a way that a NameError is not 
raised if a non-existing variable is used in the file. The file that I 
want to run is taken out of context, and some needed variables may be 
missing that are normally there when used in the intended context. OK! 
When I run it out of context, I do not want the execution to stop 
half-way through the file based on NameErrors, instead a predefined 
dummy variable should be used. The question is: Can I achieve that?

Google didn't give me much, so I experimented a bit: First, I created a 
dummy object, which is meant to be used when a variable is missing:

    class dummyClass(object):
        pass
    dummyObject = dummyClass()

The actual dummy object is supposed to be a bit more complicated than 
that. The next step was to subclass dict:

    class forgivingDict(dict):
        def __init__(self,*args,**kwargs):
            dict.__init__(self,*args,**kwargs)
        def __getitem__(self,key):
            print '    Getting', key
            try:
                return dict.__getitem__(self,key)
            except KeyError:
                return dummyObject
        def __setitem__(self,key,value):
            print '    Setting', key, 'to', value
            dict.__setitem__(self,key,value)
        def __contains__(self,item):
            return True
        def __repr__(self):
            return 'forgivingDict(%s)' % (dict.__repr__(self),)

Then I tried to execute a file using a forgivingDict() as namespace:

    ns = forgivingDict()
    execfile(filePath, ns)

A file containing the following passes perfectly OK:

    a = 0
    b = a

But a file containing the following produces a NameError:

    b = a

The error traceback for the interested:

    Traceback (most recent call last):
      File "//charm/mikael/My 
Documents/Programmering/Python/Tester/voidTest.py", line 130, in ?
        execfile('test2.py', ns)
      File "test2.py", line 1, in ?
        b = a
    NameError: name 'a' is not defined

Now, that is exactly what is to expect if ns is a dict(), but I was 
hoping that b would have ended up as dummyObject when ns is a 
forgivingDict(). One thing: Nothing is printed out when execfile-ing the 
files, which means that the methods forgivingDict.__getitem__ and 
forgivingDict.__setitem__ are never used. My guess was that the 
execution done by execfile uses dict.__getitem__(ns, key) and 
dict.__setitem__(ns,key,value) instead of ns[key] and ns[key]=value when 
getting and setting variables. That is probably intentional from the 
developers and done that way for a good reason.

Alternative test: I've tried to replace __builtin__.dict with my 
forgivingDict, slightly modified to make sure that the inheritance still 
works, which didn't change anything. So it seams that the execution done 
by execfile does *not* use dict.__getitem__(ns, key) and 
dict.__setitem__(ns,key,value) after all, but something else. Probably 
the original dict is around somewhere else, and execfile uses the 
corresponding methods of that.

My approach seems flawed. Any ideas? Can I somehow execute a complete 
file even if there are non-existent variables used somewhere? A 
try-except around the execfile statement is not an alternative, since 
that stops the execution where the error occurs.

Should I perhaps read up on the compiler module? I mean: Using the 
compiler module to analyze the content of the file, and based on that 
updating my namespace before executing the file.

/MiO



More information about the Python-list mailing list