[Python-Dev] PEP 292, Simpler String Substitutions

Raymond Hettinger python@rcn.com
Wed, 19 Jun 2002 02:45:46 -0400

From: "Barry A. Warsaw" <barry@zope.com>
> A Simpler Proposal
>     Here we propose the addition of a new string method, called .sub()
>     which performs substitution of mapping values into a string with
>     special substitution placeholders.  These placeholders are
>     introduced with the $ character.  The following rules for
>     $-placeholders apply:
>     1. $$ is an escape; it is replaced with a single $

Hmm, some strings (at least in the spam I receive) contain $$$$$$.
How about ${$}?

>     2. $identifier names a substitution placeholder matching a mapping
>        key of "identifier".  "identifier" must be a Python identifier
>        as defined in [2].  The first non-identifier character after
>        the $ character terminates this placeholder specification.


>     3. ${identifier} is equivalent to $identifier and for clarity,
>        this is the preferred form.  It is required for when valid
>        identifier characters follow the placeholder but are not part of
>        the placeholder, e.g. "${noun}ification".


> Handling Missing Keys
>     What should happen when one of the substitution keys is missing
>     from the mapping (or the locals/globals namespace if no argument
>     is given)?  There are two possibilities:
>     - We can simply allow the exception (likely a NameError or
>       KeyError) to propagate.
>     - We can return the original substitution placeholder unchanged.

       - Leave placeholder unchanged unless default argument supplied:
                  mystr.sub(mydict, undefined='***')  # Fill unknowns with
       - Raise an exception only if specified:
                  mystr.sub(mydict, undefined=NameError)
        - Return a count of the number of missed substitutions:
                  nummisses = mystr.sub(mydict)

>     BDFL proto-pronouncement: It should always raise a NameError when
>     the key is missing.  There may not be sufficient use case for soft
>     failures in the no-argument version.

I had written a minature mail-merge program and learned that the NameError
approach is a PITA.  It makes sense if the mapping is defined inside the
however, externally supplied mappings (like a mergelist) can be expected to
have "holes" and launching exceptions makes it harder to recover than having
a default behavior.  The best existing Python comparison is the
str.replace() method which does not bomb-out when the target string is not

Raymond Hettinger