[Python-Dev] exec/with thunk-handling proposal (on a new thread eventually)
holger krekel
pyth@devel.trillke.net
Mon, 3 Feb 2003 14:35:31 +0100
[sorry that this posting may double but i failed to post
this on a new thread and even 'mutt' with 120 columns
doesn't show the subject anymore]
Hello,
I'll try to take the discussion about a "unified approach"
towards 'code block' or thunk handling into a fresh thread
and present what Michael Hudson truthfully calls
"a friendly competing approach".
Preliminaries
-------------
We have some use cases for a construct that allows
encapsulating try/except/finally hooks into
an object. Especially for timely finalization (of files,
locks or other resources) we don't want to scatter
try-finally constructs all over the place.
Please understand that the following proposal has
nothing to do with "function-level" thunk-manipulation
ala classmethod but only with "inline" thunks (which
don't and shouldn't have their own scope).
Syntax and semantic proposal
----------------------------
I think we can may get away with only a "weak" keyword
and allow the aforementioned encapsulation of execution
events into an object like this:
exec expr [with params]: suite
where the expression is evaluated to return a
"thunk" handler with these optional "execution" hooks:
def __enter__(self):
"before suite start"
def __except__(self, type, value, tb):
"swallow given exception, reraise if neccessary"
def __leave__(self):
"""upon suite finish (not called if __except__
exists and an exception happened)
"""
The above "with" parameters (of the form name=expr, comma-separated)
are bound in local (or global/nested) *and* handler instance
namespace. The 'suite' is what we call "thunk".
The above logic allows clean timely finalization for
multiple ressources:
exec autoclose() with f1=open(name1), f2=open(name2, 'w'):
for line in f1:
...
f2.write(...)
which would execute as follows
a) autoclose() instance is created and stored as the
"thunk"-handler
b) f1/f2 are stored as attributes on the autoclose instance
c) f1/f2 are put into the local/global namespace (and nested ones
if rebinding is allowed)
d) thunk executes (for line ...)
e) autoclose 'leave' hook is called (with or without exception)
and is implemented like this:
def __leave__(self):
for obj in self.__dict__.values():
obj.close()
f) thunk handler is removed
Because computing 'f1' may succeed but 'f2' can subsequently
fail the assignments *have to* execute within "autoclose"
control.
Now on to the usage of the except hook. Nice use cases might be
exec retry(maxretry=3, on=IOError):
# do network io-stuff
or
exec skip_on(AttributeError, TypeError):
some_object.notify_hook()
but i am sure there are more. Exception handling is often
ugly when inlined with the code. I think that stating
'exception behaviour' up-front allows to write nice
readable constructs.
__exit__ versus __leave__
---------------------------
One remark (mainly to Michael as he does that other
patch) about the hook-name __leave__ versus __exit__.
we may want to eventually allow 'yield' within the
thunk and then '__exit__' would be misleading. Here is
the use case:
exec self.mylock: # would lock/unlock on entering/leaving
# the generator
...
for whatever in something:
yield whatever
...
Or do you think that this (future) use case warrants
yet another hook?
If there is interest i can probably modify my patch
to allow all of the proposed syntax so that you could
play around with it.
the next additional idea is not essential for my so-far
proposal (but hopefully interesting, nonetheless).
regards and interested in comments,
holger
------------- Catching values ala Quixote -------------------
With my former patch there was another "execution" event:
the catching of "dropped" values ala Quixote. For values
that are not assigned to a name and would be discarded otherwise
the execution handler can implement another hook:
def __catch__(self, value):
"catch dropped value from thunk"
this allows anonymous (un-named) objects to be passed
*within the thunk* to the execution handler.
some example use-cases:
exec debug:
if condition:
"something questionable happenend"
so you can quite completly encapsulate debug-handling
into one object. Note that this exec could be
special-cased to do nothing if "debug" is None.
Another one (ala the Quixote-framework):
exec html_stream:
"<h1>title</h1>"
"<p>%s</p>" % html_quote(para)
or even:
exec html.tr():
exec html.td(): "column"
which comes close to what Walter wants. And maybe
you understand now why I choose this strange xml-syntax with
my former patch :-) Actually i didn't have the idea of
reusing 'exec' which makes a lot more sense to me, now.
again with regards and intersted in any remarks,
holger
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
----- End forwarded message -----
--
"Why are people killing each other when there is so much fun stuff
to be had through friendly cooperation?" (Bengt Richter on c.l.py)
"Why are people killing each other when there is so much fun stuff
to be had through friendly cooperation?" (Bengt Richter on c.l.py)