Regular expression question

jepler at unpythonic.net jepler at unpythonic.net
Sat Nov 23 22:38:31 EST 2002


You're doing a number of "unpythonic" things in this code.  It's best to
learn to speak Python like a native, to get beyond building up a "phrasebook"
to translate Perl statements into Python statements.

The biggest "unpythonic" thing is referring to an arbitrary global
variable by its name at runtime.  This is very bad, since it lets a
user refer to any function.  Besides that, you'll probably encapsulate
the Python version in a module (since it's longer than a line or two),
but the Python "globals()" returns the globals of the current module,
not the calling module.

Anyway, here's an attempt at a Pythonic version of the perl code you
posted.  Yes, it's longer than the Perl version.  To use it, you'd write

        def f(s): return s.upper()
        def g(s): return s.title()
        function_map = {'f': f, 'g': g}
        print substitute_template("The lessons are: '%%f%%' and '%%g%%'",
                                  function_map, "python is not perl")
        # Test out error handling
        print substitute_template("At the tone, time time is 10PM: %%z%%",
                                  function_map,    "")

(The third argument corresponds to $variable in your example)

Here's the code to implement the 'substitute_template' function:
        import re

# Since python wouldn't just refer to a global 'variable', a Subfunc
# class records the desired argument and the function map for later use.
# You can call a Subfunc instance just like it was a plain function
        class Subfunc:
            def __init__(self, function_map, arg):
                self.function_map = function_map
                self.arg = arg

            def __call__(self, s):
                fname = s.group(1).lower()
# Error handling should probably be more sophisticated.
# But hell, it's better than terminating the whole program...
                try:
                    f = function_map[s]
                except KeyError:
                    return "*** ERROR: bad substitution %r ***" % fname
                return f(self.arg)

# Compile the regular expression, since we expect to be matching it frequently
        subre = re.compile("%%(.?)%%")

# Here's the function you call.  It creates a Subfunc instance and passes
# it on to re.sub
        def substitute_template(template, function_map, arg):
            return subre.sub(Subfunc(function_map, arg), template)

Enhancing the code to let $variable be an arbitrary parameter list
is fairly easy.  You'll need to learn about *args (and maybe **kw)
parameters, and either the f(*args, *kw) calling convention or the
apply function.

Jeff




More information about the Python-list mailing list