Some basic questions

Alex Martelli aleax at aleax.it
Thu Mar 27 06:10:21 EST 2003


Andrew Markebo wrote:

> 
> | def isalpha(c, letters=re.compile('[a-zA-Z]')):
> |     return letters.match(c) is not None
> 
> Is it just me putting the regexp compilation outside of the functions
> using them?? Or it was just an example?

It's definitely not just you (I often prefer to use globals for
this purpose, too) but neither is it "just an example" -- I was
answering a specific question about "a mechanism somewhat like
static" to have a LOCAL variable of the function computed just
once at startup.

> LettersRE=re.compile('[a-zA-Z]')
> def isalpha(c):
>      return LettersRE.match(c) is not None

Sure, this works, if you don't mind that global in your module's
namespace.  My solution that you quote has another technical
defect -- if isalpha is mistakenly called with two arguments
rather than one, *boom!*.  Another approach is a class, with
the compiled RE as instance data (but the original poster had
specifically asked not to have to quote classes) and yet
another is a closure:

def make_isalpha():
    letters = re.compile('[a-zA-Z]')
    def isalpha(c): return letters.match(c) is not None
    return isalpha
isalpha = make_isalpha()

This "stashes away" the compiled RE as a "free variable" in
isalpha, bound in its outer scope, and shares neither of the
defects of the previous solution.  You can also add a:
del make_isalpha
afterwards, since there's no reason to keep that function
name around.  Sometimes the same effect is achieved by
naming the outer and inner function the same way, but that
can be somewhat confusing...:

def isalpha():
    letters = re.compile('[a-zA-Z]')
    def isalpha(c): return letters.match(c) is not None
    return isalpha
isalpha = isalpha()


Classes are simpler to understand and less surprising than
these techniques, at least to most people, but if one, for
whatever reason, specifically wants to avoid them, closures
may often offer an alternative (as long as there's no need
to *re-bind* the names used for the 'state' held in the
outer-function -- the inner function cannot rebind those
names!).  Plain functions with default arguments are OK
too, but do suffer from the risk of being later called with
actual arguments taking the place of the 'defaults'...


Alex





More information about the Python-list mailing list