[Python-Dev] Anonymous blocks: Thunks or iterators?

Robert Brewer fumanchu at amor.org
Fri Apr 29 09:48:01 CEST 2005


> [Greg Ewing]
> > Elegant as the idea behind PEP 340 is, I can't shake
> > the feeling that it's an abuse of generators. It seems
> > to go to a lot of trouble and complication so you
> > can write a generator and pretend it's a function
> > taking a block argument.

[Guido]
> Maybe. You're not the first one saying this and I'm not saying "no"
> outright, but I'd like to defend the PEP.
> 
> There are a number of separate ideas that all contribute to PEP 340.
> One is turning generators into more general coroutines: continue EXPR
> passes the expression to the iterator's next() method (renamed to
> __next__() to work around a compatibility issue and because it should
> have been called that in the first place), and in a generator this
> value can be received as the return value of yield. Incidentally this
> makes the generator *syntax* more similar to Ruby (even though Ruby
> uses thunks, and consequently uses return instead of continue to pass
> a value back). I'd like to have this even if I don't get the block
> statement.

Completely agree. Maybe we should have PEP 340 push just that, and make
a PEP 341 independently for resource-cleanup (which assumes 340)?

> [snip]
> 
> The other problem with thunks is that once we think of them as the
> anonymous functions they are, we're pretty much forced to say that a
> return statement in a thunk returns from the thunk rather than from
> the containing function. Doing it any other way would cause major
> weirdness when the thunk were to survive its containing function as a
> closure (perhaps continuations would help, but I'm not about to go
> there :-).
> 
> But then an IMO important use case for the resource cleanup template
> pattern is lost. I routinely write code like this:
> 
>     def findSomething(self, key, default=None):
>         self.lock.acquire()
>         try:
>              for item in self.elements:
>                  if item.matches(key):
>                      return item
>              return default
>         finally:
>            self.lock.release()
> 
> and I'd be bummed if I couldn't write this as
> 
>     def findSomething(self, key, default=None):
>         block synchronized(self.lock):
>              for item in self.elements:
>                  if item.matches(key):
>                      return item
>              return default

Okay, you've convinced me. The only way I can think of to get the effect
I've been wanting would be to recompile the template function every time
that it's executed with a different block. Call it a "Python
_re_processor" ;). Although you could memoize the the resultant
bytecode, etc., it would still be pretty slow, and you wouldn't be able
to alter (rebind) the thunk once you'd entered the caller. Even then,
you'd have the cell issues you mentioned, trying to push values from the
thunk's original scope. Bah. It's so tempting on the semantic level, but
the implementation's a bear.


Robert Brewer
MIS
Amor Ministries
fumanchu at amor.org


More information about the Python-Dev mailing list