Permalink
Cannot retrieve contributors at this time
196 lines (136 sloc)
4.92 KB
| PEP: 379 | |
| Title: Adding an Assignment Expression | |
| Version: $Revision$ | |
| Last-Modified: $Date$ | |
| Author: Jervis Whitley <jervisau@gmail.com> | |
| Status: Withdrawn | |
| Type: Standards Track | |
| Content-Type: text/x-rst | |
| Created: 14-Mar-2009 | |
| Python-Version: 2.7, 3.2 | |
| Post-History: | |
| Abstract | |
| ======== | |
| This PEP adds a new assignment expression to the Python language | |
| to make it possible to assign the result of an expression in | |
| almost any place. The new expression will allow the assignment of | |
| the result of an expression at first use (in a comparison for | |
| example). | |
| Motivation and Summary | |
| ====================== | |
| Issue1714448 "if something as x:" [1]_ describes a feature to allow | |
| assignment of the result of an expression in an if statement to a | |
| name. It supposed that the ``as`` syntax could be borrowed for this | |
| purpose. Many times it is not the expression itself that is | |
| interesting, rather one of the terms that make up the | |
| expression. To be clear, something like this:: | |
| if (f_result() == [1, 2, 3]) as res: | |
| seems awfully limited, when this:: | |
| if (f_result() as res) == [1, 2, 3]: | |
| is probably the desired result. | |
| Use Cases | |
| ========= | |
| See the Examples section near the end. | |
| Specification | |
| ============= | |
| A new expression is proposed with the (nominal) syntax:: | |
| EXPR -> VAR | |
| This single expression does the following: | |
| - Evaluate the value of ``EXPR``, an arbitrary expression; | |
| - Assign the result to ``VAR``, a single assignment target; and | |
| - Leave the result of ``EXPR`` on the Top of Stack (TOS) | |
| Here ``->`` or (``RARROW``) has been used to illustrate the concept that | |
| the result of ``EXPR`` is assigned to ``VAR``. | |
| The translation of the proposed syntax is:: | |
| VAR = (EXPR) | |
| (EXPR) | |
| The assignment target can be either an attribute, a subscript or | |
| name:: | |
| f() -> name[0] # where 'name' exists previously. | |
| f() -> name.attr # again 'name' exists prior to this expression. | |
| f() -> name | |
| This expression should be available anywhere that an expression is | |
| currently accepted. | |
| All exceptions that are currently raised during invalid | |
| assignments will continue to be raised when using the assignment | |
| expression. For example, a ``NameError`` will be raised when in | |
| example 1 and 2 above if ``name`` is not previously defined, or an | |
| ``IndexError`` if index 0 was out of range. | |
| Examples from the Standard Library | |
| ================================== | |
| The following two examples were chosen after a brief search | |
| through the standard library, specifically both are from ast.py | |
| which happened to be open at the time of the search. | |
| Original:: | |
| def walk(node): | |
| from collections import deque | |
| todo = deque([node]) | |
| while todo: | |
| node = todo.popleft() | |
| todo.extend(iter_child_nodes(node)) | |
| yield node | |
| Using assignment expression:: | |
| def walk(node): | |
| from collections import deque | |
| todo = deque([node]) | |
| while todo: | |
| todo.extend(iter_child_nodes(todo.popleft() -> node)) | |
| yield node | |
| Original:: | |
| def get_docstring(node, clean=True): | |
| if not isinstance(node, (FunctionDef, ClassDef, Module)): | |
| raise TypeError("%r can't have docstrings" | |
| % node.__class__.__name__) | |
| if node.body and isinstance(node.body[0], Expr) and \ | |
| isinstance(node.body[0].value, Str): | |
| if clean: | |
| import inspect | |
| return inspect.cleandoc(node.body[0].value.s) | |
| return node.body[0].value.s | |
| Using assignment expression:: | |
| def get_docstring(node, clean=True): | |
| if not isinstance(node, (FunctionDef, ClassDef, Module)): | |
| raise TypeError("%r can't have docstrings" | |
| % node.__class__.__name__) | |
| if node.body -> body and isinstance(body[0] -> elem, Expr) and \ | |
| isinstance(elem.value -> value, Str): | |
| if clean: | |
| import inspect | |
| return inspect.cleandoc(value.s) | |
| return value.s | |
| Examples | |
| ======== | |
| The examples shown below highlight some of the desirable features | |
| of the assignment expression, and some of the possible corner | |
| cases. | |
| 1. Assignment in an if statement for use later:: | |
| def expensive(): | |
| import time; time.sleep(1) | |
| return 'spam' | |
| if expensive() -> res in ('spam', 'eggs'): | |
| dosomething(res) | |
| 2. Assignment in a while loop clause:: | |
| while len(expensive() -> res) == 4: | |
| dosomething(res) | |
| 3. Keep the iterator object from the for loop:: | |
| for ch in expensive() -> res: | |
| sell_on_internet(res) | |
| 4. Corner case:: | |
| for ch -> please_dont in expensive(): | |
| pass | |
| # who would want to do this? Not I. | |
| References | |
| ========== | |
| .. [1] Issue1714448 "if something as x:", k0wax | |
| http://bugs.python.org/issue1714448 | |
| 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 | |
| coding: utf-8 | |
| End: |