PEP 343, second look

R

Ron Adam

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
 
P

Paul Rubin

Ron Adam said:
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?)

That's not a syntactic issue. "x / y" is a syntactically valid
expression even though y==0 results in in a runtime error.
 
R

Ron Adam

Paul said:
That's not a syntactic issue. "x / y" is a syntactically valid
expression even though y==0 results in in a runtime error.

The term 'arbitrary' may be overly broad. Take for example the
description used in the 2.41 documents for the 'for' statement.

"The expression list is evaluated once; it should yield an iterable object."


If the same style is used for the with statement it would read.

"The expression, (but not an expression-list), is evaluated once; it
should yield an object suitable for use with the 'with' statement. ... "

Or some variation of this.


Regards,
Ron
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,262
Messages
2,571,059
Members
48,769
Latest member
Clifft

Latest Threads

Top