Guido van Rossum wrote: > I received this from Glyph. He brings up some interesting use cases > for thunks. I guess it could be used for "on" style event handler > declarations. Hmm, you could even craft your own case statement with > his suggestion: > > switch(expr): > case(val1): > block1 > case(val2): > block2 > default: > block3 > > This actually makes me worry -- I didn't plan thunks to be the answer > to all problems. A new idea that could cause a paradigm landslide is > not necessarily right. That's a very interesting point. Now i wonder if the following implementation report falls (partly) into this category or goes otherwise off-road. Please bear with me if it does. Recently, i implemented an experimental "execution protocol" for Python-2.2.2. It centers around "indented code blocks" and their execution. First i started out to (try to) put indented blocks into a code object and allowing to denote before-hand an object that gets and executes it. (Regarding syntax I will only mention that much for now: i experimentally tried out quite a number from the syntactic ideas that were brought up here recently). Soon i felt that trying to turn an indented block into a code object goes against the grain of the CPython implementation. Even worse, I couldn't seriously do much with a code object apart from executing (or skipping) it and dealing with exceptions. It's especially hard to construct a nice enough namespace/scope interaction between a code object and its exec-handler. Also 'execing' code often destroys optimization options. All not so nice. So i went on and tried to settle on what i really wanted: a) to allow an object to hook into certain "execution events" and especially to encapsulate error-handling which today is often "inlined": the to-be-handled code block intermingles with the enclosing try-except construct. b) to have easy ways of "exchanging parameters" between a code block and its execution handler. Without such interaction the handler and its code block would be completly orthogonal to each other (which is puristic but doesn't give you much in practise). To satisfy a) i implemented the following execution hooks (which all return None): class some_execution_handler: def __enter__(self): """called before my indented block is executed """ def __except__(self, type, value, traceback): """called if an exception occurs during execution""" def __leave__(self): """called when execution is finished. this is called if there was no exception AND if there was an exception but no __except__ hook """ Now how to do the b) "exchanging parameters" part? After some experiments I choose to do it *oneway* resp. only in the direction from code block to execution handler. The rationale is that the execution handler should only *add* behaviour but not modify "foreign" local namespaces. I think this is a crucial point. This code-to-handler communication is made explicit by specifying a series of "name=expr" bindings which (as usual) have effect in local or global scope but *additionally* are set as attributes on the execution handler instance. Thus for timely finalization you now only have to 1. specify objects to be finalized, e.g.: f1=open('...') 2. name a handler that implements __leave__ like this: def __leave__(self): for f in self.__dict__.values(): f.close() For 'acquire/release' it's even simpler: class autolock(threading.RLock): __enter__ = threading.RLock.__acquire__ __leave__ = threading.RLock.__release__ This worked nicely but soon I also wanted a way to pass *anonymous* values towards an execution handler. I went the Quixotish way and added this fourth and last hook to the execution handler: def __catch__(self, arg): """catches a dropped value ala Quixote. "dropped" means that an expression's result of the code block would otherwise be discarded. """ To summarize, the execution protocol now has three semantic aspects: - execution hooks (enter, leave, except) - local name bindings set as instance attributes - drop-catch pattern for anonymous object flow from code block to handler Now let's assume that i realized this with a XML-like syntax (which i actually did but don't see as central), then the above requirements roughly map to '<' expr (NAME '=' expr)* '>' suite The evaluated 'expr' is the execution handler and 'suite' is the code block. It's hopefully evident now how the following example usages work: <autoclose() f1=open('/etc/passwd')> data = f1.read() # here f1 will be closed no matter what def some_class_method(self, ...): ... <self.lock1> # in critical part here <debug> u"hello world" # debug object catches dropped object <async_remote> # handles the remote call including errors remote.call(...) <shell> "ls -la" if shell.errno: ... I could imagine that you find this mixture of XML syntax and python horrible. FWIW i found that this "markup" in a way resembles the notion of 'adding characteristics and meaning' to a code block much like 'html' tags do for text. However, it's certainly better to focus on semantic ideas and problems first before discussing syntactic details. In the hope of not just having wasted your time, holger
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4