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 Arnaud Delobelle
John O'Hagan resea...@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?

-- 
Arnaud
--
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 resea...@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
--
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 stdin, line 1, in module
   File stdin, 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, 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 Luis M . González
On Dec 19, 11:34 pm, John O'Hagan resea...@johnohagan.com 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


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


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


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 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 stdin, line 1, in module
  File stdin, line 5, in parrot
NameError: global name 'A' is not defined



-- 
Steven
--
http://mail.python.org/mailman/listinfo/python-list