[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:
yield
def default(self):
if self.run_default:
yield
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:
sw.case(1):
# Handle case 1
sw.case(2):
# Handle case 2
sw.default():
# 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
try:
arg = yield next_item
except:
if not hasattr(itr, "__error__"):
raise
next_item = itr.__error__(sys.exc_info()[1])
else:
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
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
More information about the Python-Dev
mailing list