Add new PEP 379 from Jervis Whitley.
This commit is contained in:
parent
f8c53dd8b3
commit
c6ac2863e5
|
@ -0,0 +1,188 @@
|
|||
PEP: 379
|
||||
Title: Adding an Assignment Expression
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Jervis Whitley <jervisau@gmail.com>
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Content-Type: text/plain
|
||||
Created: 14-Mar-2009
|
||||
Python-Version: 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 expresion:
|
||||
|
||||
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:
|
Loading…
Reference in New Issue