Re: [Tutor] executing dynamic code with exec?

2011-12-02 Thread Chris Hare
Thanks Steve for your help (and the humor).  I can see that it was a bad idea 
with your explanation.  (I just didn't want to type all that extra code :-))

I am going to re-write it using your dict approach - that looks a lot cleaner

Thanks!

Chris Hare
ch...@labr.net
http://www.labr.net

On Dec 1, 2011, at 11:25 PM, Steven D'Aprano wrote:

 Chris Hare wrote:
 
 What I am trying to do is create a set of variables based upon the table
 names in the table variables.  I have similar code which dynamically
 creates check buttons and the associated grid.  But I suspect those won't
 work either.
 What have I got wrong?
 
 Everything! wink
 
 Seriously though, your basic approach is the wrong approach. Don't try to 
 create dynamic variables like that. Suppose you succeed:
 
 varName = 'x'  # read from a file, or something
 exec('%s = 1' % varName)  # creates the variable x
 
 Great. Now you have a variable x. Later on, how do you use it?
 
 # much later on in your code...
 y = x + 1
 
 But that won't work, because you don't know that it's called x! If you knew 
 it was called x, you would have just written x = 1 early and not needed exec.
 
 Working with dynamic variable names is a pain and a nightmare. Don't do it. 
 Even if you succeed, you are making a rod for your own back: maintaining such 
 code is horrible.
 
 The right way to do this is almost always to use a data structure that maps 
 names to values, in other words, a dict.
 
 varName = 'x'  # read from a file, or something
 data = {varName: 1}
 # ...
 # much later
 y = data[varName] + 1
 
 
 In this case, something like:
 
 
 names = [Farm, Animals, AnimalTypes, Users, Roles,
Capabilities, Pedigrees, ChipMaker, Owner, Providers,
RegistryL
]
 self.cbReadTable = {}
 for name in names:
self.cbReadTable[name] = IntVar()
 
 
 And that's it. Instead of retrieving instance.cbFarmRead, use 
 instance.cbReadTable['Farm'].
 
 If you absolutely must use instance attributes, perhaps because you think 
 you're writing Javascript wink, then:
 
 for name in names:
name = 'cb' + name 'Read'
setattr(self, name, IntVar())
 
 
 And best of all, you avoid the code injection security vulnerability where 
 somebody manages to fool your code into using a list of table names like:
 
 names = [Farm, Animals, AnimalTypes, Users, Roles,
Capabilities, Pedigrees,
ChipMaker=1;import os;os.system('echo you are pwned rm-rf haha');,
Owner, Providers, RegistryL
]
 
 
 Hope your backups are really good.
 
 http://xkcd.com/327/
 
 
 
 -- 
 Steven
 
 ___
 Tutor maillist  -  Tutor@python.org
 To unsubscribe or change subscription options:
 http://mail.python.org/mailman/listinfo/tutor

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


[Tutor] executing dynamic code with exec?

2011-12-01 Thread Chris Hare

I have this code chunk:

tables = [Farm, Animals, 
AnimalTypes,Users,Roles,Capabilities,Pedigrees,ChipMaker,Owner,Providers,RegistryL]
for x in tables:
cmd = self.cb + x + Read = IntVar()
exec cmd in locals(), globals()

When the code is executed, I get the following error:

  File z.py, line 4398
exec cmd in locals(), globals()
SyntaxError: function 'showRoles' uses import * and bare exec, which are 
illegal because it contains a nested function with free variables

What I am trying to do is create a set of variables based upon the table names 
in the table variables.  I have similar code which dynamically creates check 
buttons and the associated grid.  But I suspect those won't work either.

What have I got wrong?

Thanks!

Chris___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] executing dynamic code with exec?

2011-12-01 Thread Steven D'Aprano

Chris Hare wrote:


What I am trying to do is create a set of variables based upon the table
names in the table variables.  I have similar code which dynamically
creates check buttons and the associated grid.  But I suspect those won't
work either.

What have I got wrong?


Everything! wink

Seriously though, your basic approach is the wrong approach. Don't try to 
create dynamic variables like that. Suppose you succeed:


varName = 'x'  # read from a file, or something
exec('%s = 1' % varName)  # creates the variable x

Great. Now you have a variable x. Later on, how do you use it?

# much later on in your code...
y = x + 1

But that won't work, because you don't know that it's called x! If you knew it 
was called x, you would have just written x = 1 early and not needed exec.


Working with dynamic variable names is a pain and a nightmare. Don't do it. 
Even if you succeed, you are making a rod for your own back: maintaining such 
code is horrible.


The right way to do this is almost always to use a data structure that maps 
names to values, in other words, a dict.


varName = 'x'  # read from a file, or something
data = {varName: 1}
# ...
# much later
y = data[varName] + 1


In this case, something like:


names = [Farm, Animals, AnimalTypes, Users, Roles,
Capabilities, Pedigrees, ChipMaker, Owner, Providers,
RegistryL
]
self.cbReadTable = {}
for name in names:
self.cbReadTable[name] = IntVar()


And that's it. Instead of retrieving instance.cbFarmRead, use 
instance.cbReadTable['Farm'].


If you absolutely must use instance attributes, perhaps because you think 
you're writing Javascript wink, then:


for name in names:
name = 'cb' + name 'Read'
setattr(self, name, IntVar())


And best of all, you avoid the code injection security vulnerability where 
somebody manages to fool your code into using a list of table names like:


names = [Farm, Animals, AnimalTypes, Users, Roles,
Capabilities, Pedigrees,
ChipMaker=1;import os;os.system('echo you are pwned rm-rf haha');,
Owner, Providers, RegistryL
]


Hope your backups are really good.

http://xkcd.com/327/



--
Steven

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor