[Python-Dev] Integrating PEP 310 with PEP 340

Nick Coghlan ncoghlan at gmail.com
Thu Apr 28 14:08:10 CEST 2005

Guido van Rossum wrote:
>>PEP 310 forms the basis for a block construct that I _do_ like. The question
>>then becomes whether or not generators can be used to write useful PEP 310 style
>>block managers (I think they can, in a style very similar to that of the looping
>>block construct from PEP 340).
> I've read through your example, and I'm not clear why you think this
> is better. It's a much more complex API with less power. What's your
> use case? Why should 'block' be disallowed from looping? TOOWTDI or do
> you have something better?

I'm no longer clear on why I thought what I suggested would be better either. 
Can I use the 'it was late' excuse? :)

Actually, the real reason is that I hadn't figured out what was really possible 
with PEP 340. The cases that I thought PEP 310 would handle better, I've since 
worked out how to do using the PEP 340 mechanism, and PEP 340 handles them _far_ 
more elegantly. With PEP 340, multi-stage constructs can be handled by using one 
generator as an argument to the block, and something else (such as a class or 
another generator) to maintain state between the blocks. The looping nature is a 
big win, because it lets execution of a contained block be prevented entirely.

My favourite discovery is that PEP 340 can be used to write a switch statement 
like this:

     block switch(value) as sw:
         block sw.case(1):
             # Handle case 1
         block sw.case(2):
             # Handle case 2
         block sw.default():
             # Handle default case

Given the following definitions:

     class _switch(object):
         def __init__(self, switch_var):
             self.switch_var = switch_var
             self.run_default = True

         def case(self, case_value):
             self.run_default = False
             if self.switch_var == case_value:

         def default(self):
             if self.run_default:

     def switch(switch_var):
         yield _switch(switch_var)

With the keyword-less syntax previously mentioned, such a 'custom structure' 
could look like:

     switch(value) as sw:
             # Handle case 1
             # Handle case 2
             # Handle default case

(Actually doing a switch using blocks like this would be *insane* for 
performance reasons, but it is still rather cool that it is possible)

With an appropriate utility block manager PEP 340 can also be used to abstract 
multi-stage operations. I haven't got a real use case for this as yet, but the 
potential is definitely there:

def next_stage(itr):
     """Execute a single stage of a multi-stage block manager"""
     arg = None
     next_item = next(itr)
     while True:
         if next_item is StopIteration:
             raise StopIteration
             arg = yield next_item
             if not hasattr(itr, "__error__"):
             next_item = itr.__error__(sys.exc_info()[1])
             next_item = next(itr, arg)

def multi_stage():
     """Code template accepting multiple suites"""
     # Pre stage 1
     result_1 = yield
     # Post stage 1
     yield StopIteration
     result_2 = 0
     if result_1:
         # Pre stage 2
         result_2 = yield
         # Post stage 2
     yield StopIteration
     for i in range(result_2):
         # Pre stage 3
         result_3 = yield
         # Post stage 3
     yield StopIteration
     # Pre stage 4
     result_4 = yield
     # Post stage 4

def use_multistage():
     blk = multi_stage()
     block next_stage(blk):
         # Stage 1
         continue val_1
     block next_stage(blk):
         # Stage 2
         continue val_2
     block next_stage(blk):
         # Stage 3
         continue val_3
     block next_stage(blk):
         # Stage 4
         continue val_4


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-Dev mailing list