[Python-Dev] generalized resource alloc and de-alloc (original) (raw)

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