skip to navigation
skip to content

Python Wiki

Python Insider Blog

Python 2 or 3?

Help Fund Python

[Python resources in languages other than English]

Non-English Resources

Add an event to this calendar.

Times are shown in UTC/GMT.

Add an event to this calendar.

PEP: 379
Title: Adding an Assignment Expression
Version: 98a98db9fd41
Last-Modified:  2009-03-17 19:59:58 +0000 (Tue, 17 Mar 2009)
Author: Jervis Whitley <jervisau at gmail.com>
Status: Withdrawn
Type: Standards Track
Content-Type: text/plain
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 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.