Variables in strings..

Sam Penrose see at message.body
Thu Jul 27 01:08:01 EDT 2000


In article <119330503709.20000724135021 at buz.ch>, Gabriel Ambuehl 
<gabriel_ambuehl at buz.ch> wrote:

> Hello Steve,
> Monday, July 24, 2000, 12:52:30 PM, you wrote:
> 
> >   print "Hello %s" % names[1]
> > to the eyes of anyone but a Perl afficionado.
> 
> Perhaps. But in real world (tm) CGI scripts, one needs more than just
> one variable in there. I've got Perl scripts who insert aroun 40
> variables (including array slices) during one print <<"EOF"
> instruction. I could live with the "%(myvar)" % vars() syntax if there
> would be a possibility to reference to lists and dictionary entries as
> well. Without it, it's a real pain to quickly write CGI scripts.
> Hell,
> content='<tr> <td> <a href="http://'+ pair[0] + '">' + pair[0]+ '</a> 
> </td> <td>' + pair[1] + '</td><td><a href="' + PathToScript
> etc is nothing I can consider readably. (though pair1=pair[1]
> and pair2=pair[2] would do the job but that's not really what I'd
> consider elegant...)
> 
> 
> 
> 
> 
> 
> Best regards,
>  Gabriel
> 
> 
> 

I've been doing this for about a year now, and I have to agree that 
Python string substitution syntax dominates the CGI-based systems I 
write. Some observations/habits, in no particular order and with no 
guarantee of non-obviousness.

1) It's all about dictionaries, as you noticed. Fortunately, 
dictionaries are also generally the handiest way to move data between 
HTML and databases. I tend to use tuples in situations like the example 
above, when the HTML string is short and in my script; entire pages are 
always read in from a file and coded for dictionaries.

2) Rather than assigning in that detail to a string or using vars(), 
assign to an intermediate dictionary. Your functions start to look like:
def foo():
   dict = {}
   html = CONSTANT # or open('template').read()
   for variable in otherDict.keys():
      # add to dict according to criteria
   return html % dict

3) It's helpful to create two subclasses of UserDict: one I call 
PartialStringSubstitution that leaves alone any extra %(variable)s tags 
rather than raising a KeyError and another, NoKeyErrors, that replaces 
them with empty strings rather than raising a KeyError. I can post these 
if anyone wants to see them.

4) Core control flow in my current project, a self-assembling Intranet 
which bears a family relationship to Aquarium, centers around a series 
of dictionaries:
   i. Validate user identity, determine user action, instantiate 
appropriate page object. Rest happens within object.
   ii. Parse the cgi.FieldValues(), which I instantiate with 
keep_blank_values=1, so as to cut through the irritating
if form.has_key('foo'):
   if form['foo'].value == bar:
   else:
else:
syntax. Besides checking to see if their action failed (pages with 
children can't be deleted; new pages must be given names, etc.), I 
convert the FieldValues to a regular dictionary, with image and data 
files passed off to dedicated dictionaries and methods.
   iii. If we are saving to database, assemble that dictionary now and 
save, using a utility that converts dictionaries to MySQLdb.py calls.
   iv. Define the template according to the action and start assembling 
the main dictionary, which is a PartialStringSubstitution. Many of the 
values in mainDict will themselves contain string substitution keys.
   v. After creating mainDict entries for elements common to every page,
call the heart of the heart of the system, which assembles the 
particular data that needs writing to HTML. There's a lot that needs to 
happen here (the combination of cancellable previews and uploadable 
images makes the code about three times as complicated as it would be 
without them), but basically I atomize the possibilities into a series 
of short methods that define dictionaries and update mainDict 
appropriately. Along the way I've been building yet another dictionary 
with key:value pairs that need to be inserted as hidden fields; at this 
time I assemble that into an HTML string and assign the string to 
mainDict['hiddenFields'].
   vi. Marry the template to mainDict, then marry that to the final 
NoKeyErrors dictionary, which wipes out any extra string substitution 
keys and also drops their session key (no pun intended) into all of the 
links on the page. Permissions are managed up in i.: when a user 
requests a page, the page is drawn with the information they are 
supposed to see ("You are not in this department so you can't see the 
department-only calendar; you are the owner of this page so we'll 
provide editing controls."); that way the user never sees a locked door.

5) The more I think about this, the more arbitrary it seems to have a 
medium sized (1,200 lines now; maybe twice that on ship) system so 
dominated by the need to manage string substitution syntax. OTOH, 
Python's lovely object handling makes adding things like calendars 
really easy. When I read Perl or Java I don't wish I was using them, but 
my total coding experience consists of a year of Python, so maybe I just 
don't know what I'm missing.

-- 
spenrose at well dot com



More information about the Python-list mailing list