Re: Namespaces, multiple assignments, and exec()
On Sat, 20 Dec 2008, John O'Hagan wrote: > On Sat, 20 Dec 2008, Terry Reedy wrote: > > John O'Hagan wrote: > > > 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? > > > > Put everything in your own namespace > > > > myvars={} > > for name in namelist: > >myvars[name]=func(name,args) > > Likely I'm missing something, but don't I still have to do > > var1 = myvars['var1'] > var2 = myvars['var2'] > var3 = myvars['var3'] > ...etc. > > to make the assignments? And of course I am missing the fact that I can now do the exec loop over myvars{} in the local namespace. Doing this, however, exposed some behaviour that surprises me. Inside my generator, doing: exec('foo = 7') in locals() print foo foo = 3 produces an UnboundLocalError. In case it's relevant, the error I get inside the generator if I don't specify local()s is: SyntaxError: unqualified exec is not allowed in function 'sequence_engine' it contains a nested function with free variables But doing the same thing in a simple test generator, even if it calls outside functions, works as I expect. Removing any subsequent reassignments of the same name fixes the error, and as it happens I can do this, but I'm curious, without me posting the whole generator (it's long), why doesn't the above exec() assignment work in that context? Thanks, John -- http://mail.python.org/mailman/listinfo/python-list
Re: Namespaces, multiple assignments, and exec()
On Dec 19, 11:34 pm, John O'Hagan wrote: > 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? > > Thanks, > > John Why don't you just use a dictionary? d = {} for name in name_string_list: d[name] = func(name, args) Luis -- http://mail.python.org/mailman/listinfo/python-list
Re: Namespaces, multiple assignments, and exec()
On Sat, 20 Dec 2008, Terry Reedy wrote: > John O'Hagan wrote: > > 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? > > Put everything in your own namespace > > myvars={} > for name in namelist: >myvars[name]=func(name,args) Likely I'm missing something, but don't I still have to do var1 = myvars['var1'] var2 = myvars['var2'] var3 = myvars['var3'] ...etc. to make the assignments? Regards, John -- http://mail.python.org/mailman/listinfo/python-list
Re: Namespaces, multiple assignments, and exec()
On Sat, 20 Dec 2008, Steven D'Aprano wrote: > On Sat, 20 Dec 2008 02:53:16 +, MRAB wrote: > > If you're sure you want to use the current namespace then: > > > > for name in namelist: > > vars()[name] = func(name, args) > > Doesn't work inside a function: > >>> def parrot(): > > ... for name in ['A', 'B', 'C']: > ... vars()[name] = ord(name) > ... print vars() > ... print A > ... > > >>> parrot() > > {'A': 65, 'C': 67, 'B': 66, 'name': 'C'} > Traceback (most recent call last): > File "", line 1, in > File "", line 5, in parrot > NameError: global name 'A' is not defined Historical note: I found an old post which stated that this used to work in a function which invoked exec(): http://mail.python.org/pipermail/python-list/2000-September/050840.html but I tried it in 2.5 and it doesn't any longer. Regards, John -- http://mail.python.org/mailman/listinfo/python-list
Re: Namespaces, multiple assignments, and exec()
On Sat, 20 Dec 2008, Arnaud Delobelle wrote: > John O'Hagan 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 -- http://mail.python.org/mailman/listinfo/python-list
Re: Namespaces, multiple assignments, and exec()
John O'Hagan 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? -- Arnaud -- http://mail.python.org/mailman/listinfo/python-list
Re: Namespaces, multiple assignments, and exec()
On Sat, 20 Dec 2008 02:53:16 +, MRAB wrote: > If you're sure you want to use the current namespace then: > > for name in namelist: > vars()[name] = func(name, args) Doesn't work inside a function: >>> def parrot(): ... for name in ['A', 'B', 'C']: ... vars()[name] = ord(name) ... print vars() ... print A ... >>> parrot() {'A': 65, 'C': 67, 'B': 66, 'name': 'C'} Traceback (most recent call last): File "", line 1, in File "", line 5, in parrot NameError: global name 'A' is not defined -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Namespaces, multiple assignments, and exec()
Terry Reedy wrote: John O'Hagan wrote: 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? Put everything in your own namespace myvars={} for name in namelist: myvars[name]=func(name,args) If you're sure you want to use the current namespace then: for name in namelist: vars()[name] = func(name, args) -- http://mail.python.org/mailman/listinfo/python-list
Re: Namespaces, multiple assignments, and exec()
John O'Hagan wrote: 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? Put everything in your own namespace myvars={} for name in namelist: myvars[name]=func(name,args) -- http://mail.python.org/mailman/listinfo/python-list
Namespaces, multiple assignments, and exec()
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? Thanks, John -- http://mail.python.org/mailman/listinfo/python-list