[Python-Dev] generalized resource alloc and de-alloc

Gareth McCaughan gmccaughan@synaptics-uk.com
Tue, 19 Mar 2002 18:55:15 +0000 (GMT)


In the discussion of hygienic macros, a couple of people
mentioned one particularly common family of macros: ones
that let you say things like

    withlock my_lock:
        do some stuff

and have it turn into

    my_lock.acquire()
    try:
        do some stuff
    finally:
        my_lock.release()

or something of the kind. Tim Peters even suggested (tongue
presumably in cheek) a "withlock" macro for this. Here's a
simple generalization that I've been wondering about for a
while.

Introduce a new keyword. Call it "with", for the moment,
though people who are used to "with" meaning "let me abbreviate
stuff in such-and-such a namespace" may find that strange.
Now say that

    with LHS=EXPR:
        BODY

is the same as

    TEMPNAME=EXPR
    LHS=TEMPNAME.begin()
    try:
        BODY
    finally:
        TEMPNAME.end()

except that TEMPNAME isn't exposed and maybe except that
variables named in LHS might want to live in a scope that
includes only BODY. The "LHS=" part can be omitted, with
the obvious effect.

Example 1 (rather unnecessary, of course):

    class OpenFile:
        def __init__(self, *args):
            self._args = args
        def begin(self):
            self._f = open(*self._args)
            return self._f
        def end(self):
            self._f.close()

    with f=OpenFile("foo.ps", "w"):
        f.write("%!PS\n")
        f.write("%%EOF\n")

Example 2:

    class HtmlTag:
        def __init__(self, name, **attrs):
            self._name = name
            self._attrs = attrs
        def begin(self):
            write_open_tag(self._name, self._attrs)
        def end(self):
            write_close_tag(self._name)

    with HtmlTag("table", border=1):
        for id,x,y in data:
            with HtmlTag("tr"):
                with HtmlTag("th"): write_text(id)
                with HtmlTag("td"): write_text(x)
                with HtmlTag("td"): write_text(y)

Example 3:

    class AcquiredLock:
        def __init__(self, lock):
            self._lock = lock
        def begin(self):
            self._lock.acquire()
        def end(self):
            self._lock.release()

    with AcquiredLock(my_lock):
        mutate_my_data()
        provoke_race_condition()

Alternative names, if "with" is bad for the reason
I mentioned above: "using", "with_object", "where",
"locally". I think "using" is the best of these,
but I like "with" better.

Bernhard Herzog suggested something similar, under
the name "under". That has a more complicated
interpretation, which feels a bit too specialized
to me. On the other hand, "under" is certainly
capable of saving more code than "with". On the
other other hand, it's more "implicit" and less
"explicit".

-- 
g