Namespaces, multiple assignments, and exec()

John O'Hagan research at johnohagan.com
Sat Dec 20 09:47:29 EST 2008


On Sat, 20 Dec 2008, Arnaud Delobelle wrote:
> John O'Hagan <research at johnohagan.com> writes:
> > I have a lot of repetitive assignments to make, within a generator,
> > that use a function outside the generator:
> >
> > var1 = func("var1", args)
> > var2 = func("var2", args)
> > var3 = func("var3", args)
> > etc...
> >
> > In each case the args are identical, but the first argument is a
> > string of the name being assigned. It works fine but I'd like to
> > reduce the clutter by doing the assignments in a loop. I've tried
> > using exec():
> >
> > for name in name_string_list:
> >     exec(name + ' = func(\"' + name + '\", args)')
> >
> > but in the local namespace it doesn't understand func(), and if I give
> > it globals() it doesn't understand the args, which come from within
> > the generator.
> >
> > What's a good way to do this kind of thing?
>
> Your problem is describe in too vague a way to get good answers IMHO.
> Are var1, var2, ... globals or local to the generator?  Can you give
> some sample code to show what doesn't work?

The vars are all local to the generator. This is what doesn't work (I have 
omitted some functions called by the first function for brevity):

def iterizer(options_dict):
    """Convert controllable option values to generators"""

    range_ctrls = ['length', 'variety', 'z_depth', 'z_variety']
    numerical_ctrls = ['bank', 'bell', 'channel', 'click', 'chord', 'descend',
    'divisor', 'forte', 'inv', 'large_scaly', 'metarandomt', 'metat',
    'mirrors', 'part', 'pause', 'prime', 'program', 'rand', 'randomt',
    'rotate', 'shuffle_phrase', 'split', 'small_scaly', 'tempo', 'translate',
    'transpose', 'updown' , 'voice', 'volume']
    list_ctrls = ['all_check', 'degrees', 'exclude', 'finelist', 'nondegrees',
    'include', 'only', 'pattern', 'rhythm', 'z_test']

    generators = {}
    for item in options_dict.iteritems():
        opt, value = item[0], item[1]
        if value is not None:
            if value[0] == "C":
                ctrl_opts = optparse(value[1:])
                iterator = sequence_engine(ctrl_opts)
                if opt in numerical_ctrls:
                    iterator = numerical_iter(iterator)
                elif opt in range_ctrls:
                    iterator = range_iter(iterator)
            else:
                iterator = dummy_ctrl(value)
                if opt not in list_ctrls:
                    iterator = numerical_iter(iterator)
            generators[opt] = iterator
    return generators

def inext(option, generators, options_dict):
    """Cycling version of next()"""

    if generators.has_key(option):
        try :
            return generators[option].next()
        except StopIteration:
            minidict = {option:options_dict[option]}
            minigens = iterizer(minidict)
            generators.update(minigens)
            return generators[option].next()

def sequence_engine(options):
    """Produce Sequence instances"""

    engine_opts = ['length', 'variety', 'z_depth', 'z_variety', 'descend',
    'divisor', 'forte', 'inv', 'large_scaly', 'mirrors', 'part', 'prime',
    'rand', 'rotate', 'shuffle_phrase', 'split', 'small_scaly', 'translate',
    'transpose', 'updown' , 'voice', 'all_check', 'degrees', 'exclude',
    'finelist', 'nondegrees','include', 'only', 'pattern', 'z_test', 'cardinal']
    
    engine_dict = {}
    for item in engine_opts:
        engine_dict[item] = options.__dict__[item] 
        
    generators = iterizer(engine_dict)
           
    for name in engine_opts:
             exec(name + ' = inext(\"' + name +
                        '\" ,generators, engine_dict)')

....etc..

The last loop fails to assign any names for the reasons described in the OP.

Regards,

John



More information about the Python-list mailing list