[Python-Dev] Integrating PEP 310 with PEP 340
Nick Coghlan
ncoghlan at iinet.net.au
Wed Apr 27 15:27:35 CEST 2005
This is my attempt at a coherent combination of what I like about both proposals
(as opposed to my assortment of half-baked attempts scattered through the
existing discussion).
PEP 340 has many ideas I like:
- enhanced yield statements and yield expressions
- enhanced continue and break
- generator finalisation
- 'next' builtin and associated __next__() slot
- changes to 'for' loop
One restriction I don't like is the limitation to ContinueIteration and
StopIteration as arguments to next(). The proposed semantics and conventions for
ContinueIteration and StopIteration are fine, but I would like to be able to
pass _any_ exception in to the generator, allowing the generator to decide if a
given exception justifies halting the iteration.
The _major_ part I don't like is that the block statement's semantics are too
similar to those of a 'for' loop. I would like to see a new construct that can
do things a for loop can't do, and which can be used in _conjunction_ with a for
loop, to provide greater power than either construct on their own.
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).
Block statement syntax from PEP 340:
block EXPR1 [as VAR1]:
BLOCK1
Proposed semantics (based on PEP 310, with some ideas stolen from PEP 340):
blk_mgr = EXPR1
VAR1 = blk_mgr.__enter__()
try:
try:
BLOCK1
except Exception, exc:
blk_mgr.__except__(exc)
else:
blk_mgr.__else__()
finally:
blk_mgr.__exit__()
'blk_mgr' is a hidden variable (as per PEP 340).
Note that nothing special happens to 'break', 'return' or 'continue' statements
with this proposal.
Generator methods to support the block manager protocol used by the block statement:
def __enter__(self):
try:
return next(self)
except StopIteration:
raise RuntimeError("Generator exhausted before block statement")
def __except__(self, exc):
try:
next(self, exc)
except StopIteration:
pass
def __no_except__(self):
try:
next(self)
except StopIteration:
pass
def __exit__(self):
pass
Writing simple block managers with this proposal (these should be identical to
the equivalent PEP 340 block managers):
def opening(name):
opened = open(name)
try:
yield opened
finally:
opened.close()
def logging(logger, name):
logger.enter_scope(name)
try:
try:
yield
except Exception, exc:
logger.log_exception(exc)
finally:
logger.exit_scope()
def transacting(ts):
ts.begin()
try:
yield
except:
ts.abort()
else:
ts.commit()
Using simple block managers with this proposal (again, identical to PEP 340):
block opening(name) as f:
pass
block logging(logger, name):
pass
block transacting(ts):
pass
Obviously, the more interesting block managers are those like auto_retry (which
is a loop, and hence an excellent match for PEP 340), and using a single
generator in multiple block statements (which PEP 340 doesn't allow at all).
I'll try to get to those tomorrow (and if I can't find any good use cases for
the latter trick, then this idea can be summarily discarded in favour of PEP 340).
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
More information about the Python-Dev
mailing list