[PYTHON DOC-SIG] String interpolation module
Ka-Ping Yee
kpyee@aw.sgi.com
Sun, 20 Oct 1996 23:27:03 +0900
This is a multi-part message in MIME format.
--------------237C2F1C7DE1
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
I wrote:
> I'm currently thinking of a string interpolation scheme
[...]
Robin Friedrich wrote:
>
> Dollar signs sends shivers down my spine, but carry on.
Perhaps, but i really don't see much other alternative.
Can you think of something better?
> I think this will be the most controversial of your proposals
> but well worth the debate. I'll include it as a definate topic
> at the workshop.
Thanks. Yes, i imagine it is controversial because it makes
Python look a little like other languages. But i don't think
that this reaction should overshadow its utility. Comparing
"Here is an @{[&functioncall($with, $arguments)]}." (Perl 5)
to
"Here is a $functioncall(with, arguments)." (Python + Itpl)
should help to show people that interpolation does NOT necessarily
mean riddling the entire language with punctuation. We're talking
one and only one new special character here.
To back up my proposal and give everyone (including myself!) a
chance to actually try this out and see how it feels, i've coded
up the Itpl module as i described. Because it is so short
(90 lines) i've decided to attach the module to this letter.
I hope that subscribers to this list don't mind.
The module contains the "Itpl" class and three functions:
printpl(str): interpolate and print the string 'str'
filter(file): wrap 'file' in an interpolating filter for
the 'write' method and return a new file-like object
unfilter(itplfile): unwrap the filtered 'itplfile' and
return the original file object
By default, filter and unfilter operate on "sys.stdout".
This allows you to do:
Python 1.4b3 (Oct 3 1996) [C]
Copyright 1991-1996 Stichting Mathematisch Centrum, Amsterdam
>>> from Itpl import printpl
>>> x = 3
>>> y = ['spam', (4, 6), 'eggs']
>>>
>>> printpl("The number of the count shall be $x.")
The number of the count shall be 3.
>>> printpl("This list contains $y[0], $y[1], and $y[2].")
This list contains spam, (4, 6), and eggs.
Or, to make 'print' temporarily assume this functionality:
Python 1.4b3 (Oct 3 1996) [C]
Copyright 1991-1996 Stichting Mathematisch Centrum, Amsterdam
>>> import Itpl, sys
>>> sys.stdout = Itpl.filter()
>>> z = 'python'
>>>
>>> print "$sys has been imported."
<module 'sys'> has been imported.
>>> print "$sys.stdout"
<interpolated <open file '<stdout>', mode 'w' at 10051700>>
>>> print "$z[1:]$z[0]ay"
ythonpay
>>> sys.stdout = Itpl.unfilter()
>>> print "$phew, $back $to $normal."
$phew, $back $to $normal.
Notice how Python's string slicing gives us a bit more convenience
than Perl in generating Pig Latin. :) Anyway, i'd be very grateful
if you could try it out and send me your comments.
Ping
Developer, Alias|Wavefront Inc. (Tokyo)
http://www.lfw.org/math/ brings math to the Web as easy as <se>?pi?</se>
--------------237C2F1C7DE1
Content-Type: text/plain; charset=us-ascii; name="Itpl.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="Itpl.py"
import sys, string
from types import StringType
from tokenize import tokenprog
ItplError = "ItplError"
class Itpl:
def __init__(self, fmt):
if type(fmt) != StringType:
raise TypeError, "needs string initializer"
namechars = 'abcdefghijklmnopqrstuvwxyz' \
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_';
chunks = []
pos = 0
try:
while 1:
dollar = string.index(fmt, '$', pos)
nextchar = fmt[dollar+1]
if nextchar == '{':
chunks.append((0, fmt[pos:dollar]))
pos, level = dollar+2, 1
while level:
pos = pos + tokenprog.match(fmt, pos)
tstart, tend = tokenprog.regs[3]
token = fmt[tstart:tend]
if token == '{': level = level+1
elif token == '}': level = level-1
chunks.append((1, fmt[dollar+2:pos-1]))
elif nextchar in namechars:
chunks.append((0, fmt[pos:dollar]))
pos = dollar + 1
pos = pos + tokenprog.match(fmt, pos)
while pos < len(fmt):
if fmt[pos] == '.' and \
pos+1 < len(fmt) and fmt[pos+1] in namechars:
pos = pos+2
pos = pos + tokenprog.match(fmt, pos)
elif fmt[pos] in '([':
pos, level = pos+1, 1
while level:
pos = pos + tokenprog.match(fmt, pos)
tstart, tend = tokenprog.regs[3]
token = fmt[tstart:tend]
if token[0] in '([': level = level+1
elif token[0] in ')]': level = level-1
else: break
chunks.append((1, fmt[dollar+1:pos]))
else:
chunks.append((0, fmt[pos:dollar+1]))
pos = dollar + 1 + (nextchar == '$')
except TypeError: # token regex did not match, regs[] failed
import traceback
traceback.print_exc()
raise ItplError, "unfinished expression"
except ValueError: # index did not find a dollar sign
pass
if pos < len(fmt): chunks.append((0, fmt[pos:]))
self.chunks = chunks
def __repr__(self, prog=None):
try: 1/0
except: frame = sys.exc_traceback.tb_frame
while frame.f_globals['__name__'] == name: frame = frame.f_back
loc, glob = frame.f_locals, frame.f_globals
result = []
for live, chunk in self.chunks:
if live: result.append(str(eval(chunk, loc, glob)))
else: result.append(chunk)
return string.join(result, '')
def printpl(str): print Itpl(str)
def itpl(str): return repr(Itpl(str))
class Itplfile:
def __init__(self, file): self.file = file
def __repr__(self): return '<interpolated ' + repr(self.file) + '>'
def __getattr__(self, attr): return getattr(self.file, attr)
def write(self, str): self.file.write(repr(Itpl(str)))
def filter(file=sys.stdout): return Itplfile(file)
def unfilter(ifile=None): return ifile and ifile.file or sys.stdout.file
--------------237C2F1C7DE1--
=================
DOC-SIG - SIG for the Python Documentation Project
send messages to: doc-sig@python.org
administrivia to: doc-sig-request@python.org
=================