Permalink
Cannot retrieve contributors at this time
258 lines (187 sloc)
8 KB
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| PEP: 310 | |
| Title: Reliable Acquisition/Release Pairs | |
| Version: $Revision$ | |
| Last-Modified: $Date$ | |
| Author: Michael Hudson <mwh@python.net>, | |
| Paul Moore <p.f.moore@gmail.com> | |
| Status: Rejected | |
| Type: Standards Track | |
| Content-Type: text/x-rst | |
| Created: 18-Dec-2002 | |
| Python-Version: 2.4 | |
| Post-History: | |
| Abstract | |
| ======== | |
| It would be nice to have a less typing-intense way of writing:: | |
| the_lock.acquire() | |
| try: | |
| .... | |
| finally: | |
| the_lock.release() | |
| This PEP proposes a piece of syntax (a 'with' block) and a | |
| "small-i" interface that generalizes the above. | |
| Pronouncement | |
| ============= | |
| This PEP is rejected in favor of :pep:`343`. | |
| Rationale | |
| ========= | |
| One of the advantages of Python's exception handling philosophy is | |
| that it makes it harder to do the "wrong" thing (e.g. failing to | |
| check the return value of some system call). Currently, this does | |
| not apply to resource cleanup. The current syntax for acquisition | |
| and release of a resource (for example, a lock) is:: | |
| the_lock.acquire() | |
| try: | |
| .... | |
| finally: | |
| the_lock.release() | |
| This syntax separates the acquisition and release by a (possibly | |
| large) block of code, which makes it difficult to confirm "at a | |
| glance" that the code manages the resource correctly. Another | |
| common error is to code the "acquire" call within the try block, | |
| which incorrectly releases the lock if the acquire fails. | |
| Basic Syntax and Semantics | |
| ========================== | |
| The syntax of a 'with' statement is as follows:: | |
| 'with' [ var '=' ] expr ':' | |
| suite | |
| This statement is defined as being equivalent to the following | |
| sequence of statements:: | |
| var = expr | |
| if hasattr(var, "__enter__"): | |
| var.__enter__() | |
| try: | |
| suite | |
| finally: | |
| var.__exit__() | |
| (The presence of an ``__exit__`` method is *not* checked like that of | |
| ``__enter__`` to ensure that using inappropriate objects in with: | |
| statements gives an error). | |
| If the variable is omitted, an unnamed object is allocated on the | |
| stack. In that case, the suite has no access to the unnamed object. | |
| Possible Extensions | |
| =================== | |
| A number of potential extensions to the basic syntax have been | |
| discussed on the Python Developers list. None of these extensions | |
| are included in the solution proposed by this PEP. In many cases, | |
| the arguments are nearly equally strong in both directions. In | |
| such cases, the PEP has always chosen simplicity, simply because | |
| where extra power is needed, the existing try block is available. | |
| Multiple expressions | |
| -------------------- | |
| One proposal was for allowing multiple expressions within one | |
| 'with' statement. The ``__enter__`` methods would be called left to | |
| right, and the ``__exit__`` methods right to left. The advantage of | |
| doing so is that where more than one resource is being managed, | |
| nested 'with' statements will result in code drifting towards the | |
| right margin. The solution to this problem is the same as for any | |
| other deep nesting - factor out some of the code into a separate | |
| function. Furthermore, the question of what happens if one of the | |
| ``__exit__`` methods raises an exception (should the other ``__exit__`` | |
| methods be called?) needs to be addressed. | |
| Exception handling | |
| ------------------ | |
| An extension to the protocol to include an optional ``__except__`` | |
| handler, which is called when an exception is raised, and which | |
| can handle or re-raise the exception, has been suggested. It is | |
| not at all clear that the semantics of this extension can be made | |
| precise and understandable. For example, should the equivalent | |
| code be ``try ... except ... else`` if an exception handler is | |
| defined, and ``try ... finally`` if not? How can this be determined | |
| at compile time, in general? The alternative is to define the | |
| code as expanding to a ``try ... except`` inside a ``try ... finally``. | |
| But this may not do the right thing in real life. | |
| The only use case identified for exception handling is with | |
| transactional processing (commit on a clean finish, and rollback | |
| on an exception). This is probably just as easy to handle with a | |
| conventional ``try ... except ... else`` block, and so the PEP does | |
| not include any support for exception handlers. | |
| Implementation Notes | |
| ==================== | |
| There is a potential race condition in the code specified as | |
| equivalent to the with statement. For example, if a | |
| ``KeyboardInterrupt`` exception is raised between the completion of | |
| the ``__enter__`` method call and the start of the try block, the | |
| ``__exit__`` method will not be called. This can lead to resource | |
| leaks, or to deadlocks. [XXX Guido has stated that he cares about | |
| this sort of race condition, and intends to write some C magic to | |
| handle them. The implementation of the 'with' statement should | |
| copy this.] | |
| Open Issues | |
| =========== | |
| Should existing classes (for example, file-like objects and locks) | |
| gain appropriate ``__enter__`` and ``__exit__`` methods? The obvious | |
| reason in favour is convenience (no adapter needed). The argument | |
| against is that if built-in files have this but (say) ``StringIO`` | |
| does not, then code that uses "with" on a file object can't be | |
| reused with a ``StringIO`` object. So ``__exit__ = close`` becomes a part | |
| of the "file-like object" protocol, which user-defined classes may | |
| need to support. | |
| The ``__enter__`` hook may be unnecessary - for many use cases, an | |
| adapter class is needed and in that case, the work done by the | |
| ``__enter__`` hook can just as easily be done in the ``__init__`` hook. | |
| If a way of controlling object lifetimes explicitly was available, | |
| the function of the ``__exit__`` hook could be taken over by the | |
| existing ``__del__`` hook. An email exchange [1]_ with a proponent of | |
| this approach left one of the authors even more convinced that | |
| it isn't the right idea... | |
| It has been suggested [2]_ that the "__exit__" method be called | |
| "close", or that a "close" method should be considered if no | |
| ``__exit__`` method is found, to increase the "out-of-the-box utility" | |
| of the "with ..." construct. | |
| There are some similarities in concept between 'with ...' blocks | |
| and generators, which have led to proposals that for loops could | |
| implement the with block functionality [3]_. While neat on some | |
| levels, we think that for loops should stick to being loops. | |
| Alternative Ideas | |
| ================= | |
| IEXEC: Holger Krekel -- generalised approach with XML-like syntax | |
| (no URL found...). | |
| Holger has much more far-reaching ideas about "execution monitors" | |
| that are informed about details of control flow in the monitored | |
| block. While interesting, these ideas could change the language | |
| in deep and subtle ways and as such belong to a different PEP. | |
| Any Smalltalk/Ruby anonymous block style extension obviously | |
| subsumes this one. | |
| :pep:`319` is in the same area, but did not win support when aired on | |
| python-dev. | |
| Backwards Compatibility | |
| ======================= | |
| This PEP proposes a new keyword, so the ``__future__`` game will need | |
| to be played. | |
| Cost of Adoption | |
| ================ | |
| Those who claim the language is getting larger and more | |
| complicated have something else to complain about. It's something | |
| else to teach. | |
| For the proposal to be useful, many file-like and lock-like | |
| classes in the standard library and other code will have to have :: | |
| __exit__ = close | |
| or similar added. | |
| Cost of Non-Adoption | |
| ==================== | |
| Writing correct code continues to be more effort than writing | |
| incorrect code. | |
| References | |
| ========== | |
| There are various python-list and python-dev discussions that | |
| could be mentioned here. | |
| .. [1] Off-list conversation between Michael Hudson and Bill Soudan | |
| (made public with permission) | |
| http://starship.python.net/crew/mwh/pep310/ | |
| .. [2] Samuele Pedroni on python-dev | |
| https://mail.python.org/pipermail/python-dev/2003-August/037795.html | |
| .. [3] Thread on python-dev with subject | |
| `[Python-Dev] pre-PEP: Resource-Release Support for Generators` | |
| starting at | |
| https://mail.python.org/pipermail/python-dev/2003-August/037803.html | |
| Copyright | |
| ========= | |
| This document has been placed in the public domain. | |
| .. | |
| Local Variables: | |
| mode: indented-text | |
| indent-tabs-mode: nil | |
| sentence-end-double-space: t | |
| fill-column: 70 | |
| End: |