dynamic assigments

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri Mar 25 01:44:34 EDT 2011


On Thu, 24 Mar 2011 19:51:08 -0700, scattered wrote:

> On Mar 24, 7:18 pm, Steven D'Aprano <steve
> +comp.lang.pyt... at pearwood.info> wrote:
>> On Thu, 24 Mar 2011 14:39:34 -0700, scattered wrote:
>> > Could try:
>>
>> >>>> my_list = [("x", 7), ("y", 8)]
>> >>>> for pair in my_list: exec(pair[0] + " = " + str(pair[1])) x,y
>> >>>> (7,8)
>>
>> Please don't ever do such a thing. The world has enough buggy software
>> vulnerable to code injection attacks without you encouraging newbies to
>> write more.
>>
>> If (generic) you, the programmer, can write
>>
>> my_list = [("x", 7), ("y", 8)]
>> for pair in my_list:
>>     exec(pair[0] + " = " + str(pair[1]))
>>
>> in your code, then you should stop messing about and just write:
>>
>> x = 7
>> y = 8
>>
>>
> Good question - though presumably the OP had some motivation for wanting
> to do this dynamically. Possibly some sort of code-template (though then
> it would probably make more sense to create a text file which contains
> the bindings you want, which could then be expanded to a full-fledged
> program).

Of course he has some motivation for wanting to do it. Nearly every bad 
idea ever done was done because somebody thought it was a good idea. 
Templating via exec was a bad idea the first time somebody thought "I 
know! I'll just use exec to create variables!" and it remains a bad idea 
today. 

(Although with care and a lot of effort, you can make it less bad. See, 
for example, namedtuple in the standard library. Read the source code for 
it, and see just how much effort Raymond Hettinger puts into making it 
safe. And call me paranoid if you like, but I still wouldn't trust it if 
the names were coming from anonymous users over the internet and injected 
straight into namedtuple. Just because *I* can't see a vulnerability, 
doesn't mean there isn't one.)



>> instead. The only time this technique is even *possibly* justified is
>> if the contents of my_list comes from external data not known at
>> compile- time.
> 
> Here is another possibility: you are using Python *interactively* in

In my earlier post, I described the dynamic creation of variables as:

"... something you should *nearly* always avoid doing." [Emphasis added.]

Congratulations, you've found one of the few exceptions. Of course an 
interactive shell must allow you to create variables interactively. It 
would hardly be interactive if you couldn't. This is why interactive 
shells are often called a REPL: Read Eval (or Exec) Print Loop.

Note also that I was describing *variables*. Although there are a lot of 
similarities between variables and instance attributes (so much so that 
some other languages call them both variables), there are some subtle 
differences, and those differences are important. Dynamic *attribute* 
creation is not anywhere near as bad a code-smell as dynamic variables:

setattr(instance, name, value)  # A slight whiff, but usually okay.

globals()[name] = value  # Smells pretty bad, but very occasionally okay.

exec(name + " = " + str(value))  # Reeks like Satan's armpit after a long
# day mucking out the pits of excrement with the souls of the Damned.


> solving cryptograms (as a matter of fact - I was doing exactly this
> yesterday in trying to solve some Playfair ciphers).

If you're interested in ciphers, you might find this useful:

http://pypi.python.org/pypi/obfuscate



 You have a
> ciphertext that is a stream of letters in the range A...Z. You need to
> consult frequencies of letters, pairs of letters, triples of letters,
> and quadruples of letters that occur. So, you write a script that steps
> through the cipher text, creates a dictionary which records frequencies
> of strings of length <= 4, and, as an added convienence, creates
> bindings of frequencies to these strings.

I don't call that a convenience. I call that a problem. What happens when 
your cipher text includes

"...aBzNk6YPq7psGNQ1Pj?lenprem1zGWdefmspzzQ..."

How many problems can you see there?



> Thus - if you want to know how
> often, say, EFW occurs in the ciphertext you just type EFW (rather than
> freq["EFW"]) and the Python shell returns the frequency.

Sounds like a terrible idea. What do you do when you want to know how 
often "len" or "1xy" or "???" or "def" occurs?



-- 
Steven



More information about the Python-list mailing list