Replacing globals in exec by custom class

Discussion in 'Python' started by Jonathan S, Dec 8, 2010.

  1. Jonathan S

    Jonathan S Guest

    Hi all,

    I wonder if anyone can explain some weird behaviour in Python.
    What I'm trying to do is to execute a string of python code through
    the 'exec' statement. I pass an instance of my Global class, which
    acts like a dict. By overriding the __getitem__ method, the Global
    should pretend that a global variable, named 'xx' does exist.

    This does work for the outermost scope in the executed code, but
    inside the nested function, 'q', the Global instance seems never to be
    accessed, 'xx' is not found, while the globals() built-in still
    returns the custom Global instance.

    According to python's executing model [1], the interpreter is supposed
    to look into globals(), if a variable has not been assigned in the
    inner scope. What am I missing here?

    [1] http://docs.python.org/reference/executionmodel.html


    {{{
    class Global(dict):
    def __init__(self):
    pass
    def __getitem__(self, key):
    import __builtin__
    if key == 'xx':
    return 'xx'

    if hasattr(__builtin__, key):
    return getattr(__builtin__, key)

    else key in self.__dict__:
    return self.__dict__[key]

    def __setitem__(self, key, value):
    self.__dict__[key] = value

    def __str__(self):
    return ' <globals> ' + unicode(self.__dict__)


    code="""
    print globals()
    print xx # Does work, prints 'xx'

    def q():
    print globals().__getitem__('xx') # Does work, prints 'xx'
    print globals()['xx'] # Does work, prints 'xx'
    print xx # Does not work, cannot find xx
    q()
    """
    g = Global()

    exec(compile(code, 'my code', 'exec'), g, g)
    }}}
    Jonathan S, Dec 8, 2010
    #1
    1. Advertising

  2. Jonathan S

    DevPlayer Guest

    Couple of things:

    I don't think this is what you want:

    def __getitem__(self, key):
    import __builtin__
    if key == 'xx':
    return 'xx'
    I won't return a KeyError for any string you give g[]
    It will return 'xx' only if you supply key='xx' and ignore every other
    key=???
    With the above code you can do g['yyy'] and you would get None

    For your example code to work, line 14 in your example needs to be:
    elif key in self.__dict__: # (change else to elif)

    for your dict (or globalscl) to act like other dicts() add
    an else:
    raise KeyError( 'Key not found: %s' % (key,))

    __dict__ of a dict I believe is not the namespace of dict. I thought
    dict[key] and dict.__dict__[key] where not the same place

    __dict__ of dict in Python 2.5 and prior was rumored to be buggy and
    unused. Don't know about Python 2.6 +

    I thought __getitem__() did not look in __dict__ of dict().

    If I copy your code into a module globalcl.py
    and comment out "print xx" in the string,
    and in PyCrust I "import globalcl"
    I too get the results and errors you claim.

    If I then do:

    >>>globalcl.g.keys()

    I get: ['__builtins__']

    >>>globalcl.g['__builtins__']

    I get: nothing (or None)

    >>>globalcl.g['__builtin__']

    I get: nothing (or None)

    # -------------------------
    # interesting part

    >>>globalcl.g['xx']

    I get: 'xx'

    >>>if 'xx' in globalcl.g:

    .... print True
    ....else:
    .... print False

    I get: False
    # -------------------------

    >>>globalcl.g.__builtins__

    AttributeError: 'Global' object has no attribute __builtins__'

    >>>globalcl.g.__builtins__

    AttributeError: 'Global' object has no attribute '__builtin__'

    >>>globalcl.g.__dict__

    {'q': <function q at 0x01C738B0>}
    DevPlayer, Dec 8, 2010
    #2
    1. Advertising

  3. Jonathan S

    DevPlayer Guest

    Shouldn't
    return 'xx'
    be
    return self['xx']
    DevPlayer, Dec 8, 2010
    #3
  4. Jonathan S

    DevPlayer Guest

    Shouldn't
    return 'xx'
    be
    return self['xx'


    I don't know why precisely you're using a class as a global namespace,
    not that I personally find fault with it. But here are some other
    things you can do.

    Idea one:
    ======================================================
    class NS(object): """place to put junk"""

    ns = NS()

    ns.global_var1 = "SPAM and eggs"
    ns.global_var2 = "use as you like just prefix with ns."
    del ns.global_var # because I'm fickle
    dir(ns)

    Idea two:
    ======================================================
    Instead of a class as a global namespace, use a module

    ns.py
    ------
    """My global namespace"""
    # do not import anything or make
    # classes or run functions here, just a place to have varibles

    ns_var = "var defined in ns.py"

    ignore = ['__builtins__', '__class__', '__delattr__', '__dict__',
    '__doc__', '__file__', '__format__', '__getattribute__', '__hash__',
    '__init__', '__name__', '__new__', '__package__', '__reduce__',
    '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
    '__subclasshook__']

    main.py
    --------
    import ns
    import mod1
    import mod2
    import mod3

    ns.main_var = "this is main var"

    ns.mod3_var = mod3.mod3_var
    ns.mod3_somefunc_var = mod3.somefunc.somefunc_var

    mod3.show( "ns.ns_var", ns.ns_var)
    mod3.show( "ns.main_var", ns.main_var)
    mod3.show( "ns.mod1_var", ns.mod1_var)
    mod3.show( "ns.mod2_var", ns.mod2_var)
    mod3.show( "ns.somefunc_var", ns.somefunc_var)
    mod3.show( "ns.mod3_var", ns.mod3_var)
    mod3.show( "ns.mod3_somefunc_var", ns.mod3_somefunc_var)
    mod3.show( "dir(ns)", dir(ns))
    mod3.list_globals()


    mod1.py
    -------
    import ns

    # good usage; var not in mod1 global namespace and value is not copied
    # from one namespace to another but just put in it.

    ns.mod1_var = "this is text in mod1"

    # therefore by doing this your code in mod1 is likely to use
    # ns.mod1_var and not just mod1_var -is- not ns.mod1_var


    mod2.py
    -------
    import ns

    ns.mod2_var = "text in mod2"


    def somefunc():
    # good app globals
    ns.somefunc_var = "make a var not in the global namespace of the
    mod2"
    ns.renamed_var = "rename this"

    somefunc()



    mod3.py
    -------
    # mod3_var is misleading; because you might use it but mod3.mod3_var
    # would not be the same value as the ns.mod3_var
    mod3_var = "not assigned to ns from in mod3.py but from main.py"


    def somefunc():
    # bad globals
    somefunc.somefunc_var = "make a var not in the global namespace of
    the mod3"
    somefunc.renamed_var = "rename this"

    somefunc() # instinate somefunc_var

    def show(astring, avalue):
    print astring
    print ' ', str(avalue)

    def list_globals():
    print 'ns variable list'
    import ns
    print ' [',
    for item in dir(ns):
    if not item in ns.ignore:
    print "'" + item.strip() + "', ",
    print ']'
    DevPlayer, Dec 8, 2010
    #4
  5. Jonathan S

    Terry Reedy Guest

    On 12/8/2010 8:01 AM, Jonathan S wrote:

    > class Global(dict):
    > def __init__(self):
    > pass
    > def __getitem__(self, key):
    > import __builtin__
    > if key == 'xx':
    > return 'xx'
    >
    > if hasattr(__builtin__, key):
    > return getattr(__builtin__, key)
    >
    > else key in self.__dict__:
    > return self.__dict__[key]


    syntax error

    > def __setitem__(self, key, value):
    > self.__dict__[key] = value
    >
    > def __str__(self):
    > return '<globals> ' + unicode(self.__dict__)
    >
    >
    > code="""
    > print globals()
    > print xx # Does work, prints 'xx'
    >
    > def q():
    > print globals().__getitem__('xx') # Does work, prints 'xx'
    > print globals()['xx'] # Does work, prints 'xx'
    > print xx # Does not work, cannot find xx
    > q()
    > """
    > g = Global()
    >
    > exec(compile(code, 'my code', 'exec'), g, g)
    > }}}


    When asking such questions, paste both the actual code that compiled and
    ran and the actual traceback you got in response.

    --
    Terry Jan Reedy
    Terry Reedy, Dec 8, 2010
    #5
  6. Jonathan S

    Jonathan S Guest

    Thanks for your response! (And sorry about the syntax error, I forgot
    to test my code after cleaning up some debug statements before
    posting, the else should have been elif indeed.)

    It's very interesing, how Python works internally. According to a
    thread on the Python mailing list in 2002, it seems that the
    implementation of CPython bypasses __getitem__ of the dict object,
    when it is used as Global namespace. (For performance reasons.)

    http://mail.python.org/pipermail/python-dev/2002-October/029753.html
    Jonathan S, Dec 9, 2010
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Giles Brown

    Question about "exec in globals, locals"

    Giles Brown, Jul 4, 2003, in forum: Python
    Replies:
    2
    Views:
    341
    Adrien Di Mascio
    Jul 4, 2003
  2. tedsuzman
    Replies:
    2
    Views:
    7,057
    Michel Claveau, résurectionné d'outre-bombe inform
    Jul 21, 2004
  3. Ted
    Replies:
    1
    Views:
    448
    Duncan Booth
    Jul 22, 2004
  4. Replies:
    2
    Views:
    352
  5. Helmut Jarausch

    exec with partial globals

    Helmut Jarausch, Oct 30, 2012, in forum: Python
    Replies:
    5
    Views:
    225
    Dave Angel
    Oct 30, 2012
Loading...

Share This Page