Guido van Rossum wrote: > I've written up the specs for my "PEP 340 redux" proposal as a > separate PEP, PEP 343. > > http://python.org/peps/pep-0343.html > > Those who have been following the thread "Merging PEP 310 and PEP > 340-redux?" will recognize my proposal in that thread, which received > mostly positive responses there. > > Please review and ask for clarifications of anything that's unclear.
On the keyword front, the two keyword choices affect the naming conventions of templates differently, and I think need to be considered in that light. The naming convention for 'do' is shown in the current PEP 343. The issue I've noticed with it is that *functions* read well, but methods don't because things get out of sequence. That is, "do locking(the_lock)" reads well, but "do the_lock.locking()" does not. Whereas, using 'with', it can be written either way, and still read reasonably well ("with locked(the_lock)", "with the_lock.locked()"). The 'with' keyword also reads better if objects natively support use in 'with' blocks ("with the_lock", "with the_file"). Guido's concern regarding file objects being reused inappropriately can be dealt with in the file __enter__ method: def __enter__(self): if self.closed: raise RuntimeError, "Cannot reopen closed file handle" Template generators have the exact same problem with reusability - the solution used there is raising a RuntimeError when __enter__() is called inappropriately. This would make sense as a standard idiom - if a statement template can't be reused, attempting to do so should trigger a RuntimeError the second time __enter__() is invoked. For files, it may then become the common practice to keep pathnames around, rather than open file handles. When you actually needed access to the file, the existing "open" builtin would suffice: with open(filename, "rb") as f: for line in f: print line I've written out the PEP 343 examples below, assuming types acquire native with statement support (including Decimal contexts - I also give PEP 343 style code for Decimal contexts). PEP343 examples: 'with' keyword, native support in objects 1. A template for ensuring that a lock, acquired at the start of a block, is released when the block is left: # New methods on lock objects def __enter__(self): self.acquire() def __exit__(self, *args): self.release() Used as follows: with myLock: # Code here executes with myLock held. The lock is # guaranteed to be released when the block is left (even # if via return or by an uncaught exception). 2. A template for opening a file that ensures the file is closed when the block is left: # New methods on file objects def __enter__(self): if self.closed: raise RuntimeError, "Cannot reopen closed file handle" def __exit__(self, *args): self.close() Used as follows: with open("/etc/passwd") as f: for line in f: print line.rstrip() 3. A template for committing or rolling back a database transaction; this is written as a class rather than as a decorator since it requires access to the exception information: class transaction: def __init__(self, db): self.db = db def __enter__(self): self.db.begin() def __exit__(self, *args): if args and args[0] is not None: self.db.rollback() else: self.db.commit() Used as follows: with transaction(db): # Exceptions in this code cause a rollback 5. Redirect stdout temporarily: @with_template def redirected_stdout(new_stdout): save_stdout = sys.stdout sys.stdout = new_stdout yield None sys.stdout = save_stdout Used as follows: with open(filename, "w") as f: with redirected_stdout(f): print "Hello world" This isn't thread-safe, of course, but neither is doing this same dance manually. In a single-threaded program (e.g., a script) it is a totally fine way of doing things. 6. A variant on opening() that also returns an error condition: @with_template def open_w_error(filename, mode="r"): try: f = open(filename, mode) except IOError, err: yield None, err else: yield f, None f.close() Used as follows: with open_w_error("/etc/passwd", "a") as f, err: if err: print "IOError:", err else: f.write("guido::0:0::/:/bin/sh\n") 7. Another useful example would be an operation that blocks signals. The use could be like this: from signal import blocked_signals with blocked_signals(): # code executed without worrying about signals An optional argument might be a list of signals to be blocked; by default all signals are blocked. The implementation is left as an exercise to the reader. 8. Another use for this feature is the Decimal context. # New methods on decimal Context objects def __enter__(self): self._old_context = getcontext() setcontext(self) def __exit__(self, *args): setcontext(self._old_context) Used as follows: with decimal.Context(precision=28): # Code here executes with the given context # The context always reverts after this statement For comparison, the equivalent PEP 343 code is: @do_template def with_context(context): old_context = getcontext() setcontext(context) yield None setcontext(old_context) Used as: do decimal.with_context(decimal.Context(precision=28)): # Code here executes with the given context # The context always reverts after this statement -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.blogspot.com _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com