pre-PEP: Simple Thunks

Steven Bethard steven.bethard at gmail.com
Sun Apr 17 22:24:41 EDT 2005


Brian Sabbey wrote:
> used, but rarely is because doing so would be awkward.  Probably the 
> simplest real-world example is opening and closing a file.  Rarely will 
> you see code like this:
> 
> def with_file(callback, filename):
>     f = open(filename)
>     callback(f)
>     f.close()
> 
> def print_file(file):
>     print file.read()
> 
> with_file(print_file, 'file.txt')
> 
> For obvious reasons, it usually appears like this:
> 
> f = open('file.txt')
> print f.read()
> f.close()
> 
> Normally, though, one wants to do a lot more than just print the file. 
> There may be many lines between 'open' and 'close'.  In this case, it is 
> easy to introduce a bug, such as returning before calling 'close', or 
> re-binding 'f' to a different file (the former bug is avoidable by using 
> 'try'/'finally', but the latter is not).  It would be nice to be able to 
> avoid these types of bugs by abstracting open/close.  Thunks allow you 
> to make this abstraction in a way that is more concise and more readable 
> than the callback example given above:
> 
> do f in with_file('file.txt'):
>     print f.read()
> 
> Thunks are also more useful than callbacks in many cases since they 
> allow variables to be rebound:
> 
> t = "no file read yet"
> do f in with_file('file.txt'):
>     t = f.read()
> 
> Using a callback to do the above example is, in my opinion, more difficult:
> 
> def with_file(callback, filename):
>     f = open(filename)
>     t = callback(f)
>     f.close()
>     return t
> 
> def my_read(f):
>     return f.read()
> 
> t = with_file(my_read, 'file.txt')
> 

Definitely put this example into the PEP.  I didn't really understand 
what you were suggesting until I saw this example.  All the other ones 
you gave just confused me more.

>> When I see 'do', it reminds me of 'do loops'. That is 'Do' involves
>> some sort of flow control.  I gather you mean it as do items in a
>> list, but with the capability to substitute the named function.  Is
>> this correct?
> 
> I used 'do' because that's what ruby uses for something similar.  It can 
> be used in a flow control-like way, or as an item-in-a-list way.

Please spend some time in the PEP explaining why you chose the keywords 
you chose.  They gave me all the wrong intuitions about what was 
supposed to be going on, and really confused me.  I also got mixed up in 
when you were talking about parameters to the thunk, and when you were 
talking about parameters to the function that is called with the thunk 
as a parameter.

I'd also like to see you start with the full example syntax, e.g.:

     do <unpack_list> in <returnval> = <callable>(<params>):
         <code>

And then explain what each piece does more carefully.  Something like:

"""
When a do-statement is executed, first <callable> is called with the 
parameters <params>, augmented by the thunk object, e.g.

     do func(4, b=2):
         ...

would call

     func(thunk_obj, 4, b=2)

Next, the body of the function is executed.  If the thunk object is 
called, then <code> will be executed with the names in <unpack_list> 
bound to the objects with which the thunk was called, e.g.

     def func(thunk):
         thunk(1, y=2)
     do x, y, z=4 in func():
         print x, y, z

would call:

     func(thunk_obj)
         thunk(1, y=2)

and thus x, y and z would be bound to 1, 2 and 4 and the body of the 
thunk would be executed, printing "1 2 4".

The code in <callable> is then resumed, and the process is repeated 
until <callable> returns.  Note that this means that each additional 
call to the thunk object will cause another execution of <code>, with 
potentially different bindings for the names in <unpack_list>.

When the function finally returns, the return value will be bound to 
<returnval>, e.g.:

     def func(thunk):
         thunk()
         thunk()
         return True
     do r = func():
         print "thunk called"
     print r

would print "thunk called" twice as the body of the thunk is executed 
for each call to thunk() in func, and then would print "True" in the 
code following the do-statement.
"""

Not sure if I actually understood everything right, but you definitely 
need a much more throrough walkthrough of what happens with a thunk -- 
it's not clear at all from the current pre-PEP.

STeVe



More information about the Python-list mailing list