Re: Namespaces, multiple assignments, and exec()

2008-12-21 Thread John O'Hagan
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()

2008-12-20 Thread Luis M . González
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()

2008-12-20 Thread John O'Hagan
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()

2008-12-20 Thread John O'Hagan
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()

2008-12-20 Thread John O'Hagan
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()

2008-12-20 Thread Arnaud Delobelle
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()

2008-12-19 Thread Steven D'Aprano
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()

2008-12-19 Thread MRAB

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()

2008-12-19 Thread Terry Reedy

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()

2008-12-19 Thread John O'Hagan
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