[Python-Dev] exec/with thunk-handling proposal (original) (raw)
holger krekel pyth@devel.trillke.net
Mon, 3 Feb 2003 14:09:34 +0100
- Previous message: [Python-Dev] Acquire/release functionality
- Next message: [Python-Dev] exec/with thunk-handling proposal
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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
- Previous message: [Python-Dev] Acquire/release functionality
- Next message: [Python-Dev] exec/with thunk-handling proposal
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]