[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