PEP 343, second look
Ron Adam
rrr at ronadam.com
Wed Jun 22 15:44:44 EDT 2005
After taking a break from following PEP 343 and it's associated PEPs, I
wanted to look at it again because it still seemed a bit hard to get my
mind around.
http://www.python.org/peps/pep-0343.html
> A new statement is proposed with the syntax:
>
> with EXPR as VAR:
> BLOCK
>
> Here, 'with' and 'as' are new keywords; EXPR is an arbitrary
> expression (but not an expression-list) and VAR is a single
> assignment target.
How is EXPR arbitrary? Doesn't it need to be or return an object that
the 'with' statement can use? (a "with" object with an __enter__ and
__exit__ method?)
And if so, what is the minimum 'with' class needed to create such an
object? It would need an __exit__ method, because there would be no
point if it didn't have one. Does it absolutely need an __enter__
method? Are there any uses that might not require an __enter__?
Presuming __enter__ is always needed, would this be a minimum class that
returns a 'with' object?
class With(object):
def __enter__(self):
pass
def __exit__(self):
pass
A 'with-generator' object would need __enter__ and __exit__ methods, and
a try-yield-finally generator. Is there a name for a 'with-generator'
object? (a witherator ?)
It's possible that a function may be used that returns an
'with-generator' object and would be used in the same way that range()
is used in 'for' statements.
func with_gen(func, *args, **args):
wg = WithGen()
wg.gen = func(*arg, **args)
return wg
Which would use a generic with-generator base class.
class WithGen(object):
def gen(self): # Should this raise an error
try: # if it does't get over ridden?
yield None
finally:
pass
def __enter__(self):
try:
return self.gen.next()
except StopIteration:
raise RuntimeError("generator didn't yield")
def __exit__(self, type, value, traceback):
if type is None:
try:
self.gen.next()
except StopIteration:
print "file closed by with statement"
return
else:
raise RuntimeError("generator didn't stop")
else:
try:
self.gen.throw(type, value, traceback)
except (type, StopIteration):
return
else:
raise RuntimeError("generator caught exception")
And used like this:
def opening(filename, mode):
f = open(filename, mode)
try:
yield f
finally:
f.close()
with with_gen(opening, "testfile", "w") as f:
f.write("test file")
This seems (to me) to be an easier to understand alternative to the
decorator version. The class could also be used as a base class for
constructing other 'with' class's as well as the with_template decorator.
Will this work or am I missing something? Any suggestions for a
different (better) name for the with_gen function?
Regards,
Ron
More information about the Python-list
mailing list