[Tutor] executing dynamic code with exec?

Chris Hare chare at labr.net
Fri Dec 2 13:39:00 CET 2011


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
chare at 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 at python.org
> To unsubscribe or change subscription options:
> http://mail.python.org/mailman/listinfo/tutor

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tutor/attachments/20111202/6aa46f39/attachment.html>


More information about the Tutor mailing list