Macros in Python?

Beni Cherniavsky cben at techunix.technion.ac.il
Fri Apr 11 08:29:20 EDT 2003


Dominic wrote on 2003-04-09:

> (defmacro with-root-privs (() &body body)
>    (let ((oldidsym (gensym)))
>      `(let ((,oldidsym (geteuid)))
>         (seteuid 0)
>         (unwind-protect
> 	   (progn , at body)
> 	 (seteuid ,oldidsym)))))
>
> Is there an easy way to produce similar code
> in Python which gurantees that certain things
> happen around some code? (Maybe by using
> generators?)
>
To complete the list of solutions, there is an evil way to abstract
try..finally that is not recommended due to it's unreadability to
anybody that doesn't know the trick.  It also only works in CPython
with reference counting that invokes __del__ immediately.

The basic idea was to use a for loop and a generator:

def with_root_privs():
    oldid = geteuid()
    seteuid(0)
    yield None # dummy
    seteuid(oldid)

for _ in with_root_privs:  # `_` is dummy
    # Dohere whatever you wanted.  The generator will cause this to be
    # executed exactly once, with pre- and post- code excuted...

The problem, of course is that the for loop's body can raise an
exception, or exit the loop in other evil ways.  Luckily in CPython,
exiting the loop immediately drops the only reference to the
generator, so hooking it's __del__ would do the trick.  Writing it as
an iterator class instead of a generator would be be ugly but we can
only do it once, by a universal wrapper taking a naive generator and
returning a safe one.  Google for "abstracting try..finally with
generators" in c.l.py if you are interested.  Again, it's hard to
recommend this hack.  Instead, consider pushing PEP 310 :-).

-- 
Beni Cherniavsky <cben at tx.technion.ac.il>

Never spend several weeks on a single homework - or you will miss a
nice Linux conference ;-(.





More information about the Python-list mailing list