[Python-Dev] Re: Alternative Implementation for PEP 292:Simple String Substitutions

Tim Peters tim.peters at gmail.com
Sun Sep 5 06:32:33 CEST 2004


[Paul Moore]
>> Would it be useful to factor out the "identifier syntax" bit of the
>> pattern? The "escaped" and "bogus" groups are less likely to need
>> changing than what constitutes an identifier.
 
[Barry Warsaw]
> And if they did, you'd want to change them both at the same time.  Do
> you have any ideas for an efficient, easily documented implementation?

You'll rarely hear me say this <wink>, but fiddling classes at class
creation time is exactly what metaclasses are for.  For example,
suppose you said a Template subclass could define a class variable
`idpat`, containing a regexp matching that subclass's idea of "an
identifier".

Then we could define a metaclass once-and-for-all, like so:

class _TemplateFiddler(type):

    pattern = r"""
        (?P<escaped>\${2})|     # Escape sequence of two $ signs
        \$(?P<named>%s)|        # $ and a Python identifier
        \${(?P<braced>%s)}|     # $ and a brace delimited identifier
        (?P<bogus>\$)           # Other ill-formed $ expressions
    """

    def __init__(cls, name, bases, dct):
        super(_TemplateFiddler, cls).__init__(name, bases, dct)
        idpat = cls.idpat
        cls.pattern = _re.compile(_TemplateFiddler.pattern % (idpat, idpat),
                                  _re.IGNORECASE | _re.VERBOSE)

That substitutes the idpat regexp into the base pattern in two spots,
compiles it, and attaches the result as the `pattern` attribute of the
class being defined.

The definition of Template changes like so:

class Template(unicode): # same
    """A string class for supporting $-substitutions.""" # same

    __metaclass__ = _TemplateFiddler  # this is new
    __slots__ = [] # same

    idpat = r'[_a-z][_a-z0-9]*'  # this repaces the current `pattern`

    # The rest is the same.

While the implementation relies on understanding metaclasses, users
don't have to know about that.  The docs are easy ("define a class
vrbl `idpat`"), and it's as efficient as if subclasses had compiled
the full regexp themselves.  Indeed, you can do any amount of
computation once in the metaclass __init__, and cache the results in
attributes of the class.


More information about the Python-Dev mailing list