diff --git a/pep-3132.txt b/pep-3132.txt index 23e2c87ed..b11dadc9d 100644 --- a/pep-3132.txt +++ b/pep-3132.txt @@ -44,49 +44,109 @@ is replaced by the cleaner and probably more efficient:: For more complex unpacking patterns, the new syntax looks even cleaner, and the clumsy index handling is not necessary anymore. +Also, if the right-hand value is not a list, but an iterable, it +has to be converted to a list before being able to do slicing; to +avoid creating this temporary list, one has to resort to :: + + it = iter(seq) + first = it.next() + rest = list(it) + Specification ============= A tuple (or list) on the left side of a simple assignment (unpacking is not defined for augmented assignment) may contain at most one -expression prepended with a single asterisk. For the rest of this -section, the other expressions in the list are called "mandatory". +expression prepended with a single asterisk (which is henceforth +called a "starred" expression, while the other expressions in the +list are called "mandatory"). This designates a subexpression that +will be assigned a list of all items from the iterable being unpacked +that are not assigned to any of the mandatory expressions, or an +empty list if there are no such items. -Note that this also refers to tuples in implicit assignment context, -such as in a ``for`` statement. +For example, if ``seq`` is a slicable sequence, all the following +assignments are equivalent if ``seq`` has at least three elements:: -This designates a subexpression that will be assigned a list of all -items from the iterable being unpacked that are not assigned to any -of the mandatory expressions, or an empty list if there are no such -items. + a, b, c = seq[0], seq[1:-1], seq[-1] + a, *b, c = seq + [a, *b, c] = seq It is an error (as it is currently) if the iterable doesn't contain enough items to assign to all the mandatory expressions. +It is also an error to use the starred expression as a lone +assignment target, as in :: + + *a = range(5) + +This, however, is valid syntax:: + + *a, = range(5) + +Note that this proposal also applies to tuples in implicit assignment +context, such as in a ``for`` statement:: + + for (a, *b) in [(1, 2, 3), (4, 5, 6, 7)]: + print(b) + +would print out :: + + [2, 3] + [5, 6, 7] + Implementation ============== -The proposed implementation strategy is: +Grammar change +-------------- -- add a new grammar rule, ``star_test``, which consists of ``'*' - test`` and is used in test lists -- add a new ASDL type ``Starred`` to represent a starred expression -- catch all cases where starred expressions are not allowed in the AST - and symtable generation stage -- add a new opcode, ``UNPACK_EX``, which will only be used if a - list/tuple to be assigned to contains a starred expression -- change ``unpack_iterable()`` in ceval.c to handle the extended - unpacking case +This feature requires a new grammar rule:: -Note that the starred expression element introduced here is universal -and could be used for other purposes in non-assignment context, such -as the ``yield *iterable`` proposal. + star_expr: ['*'] expr -The author has written a draft implementation, but there are some open -issues which will be resolved in case this PEP is looked upon -benevolently. +In these two rules, ``expr`` is changed to ``star_expr``:: + + comparison: star_expr (comp_op star_expr)* + exprlist: star_expr (',' star_expr)* [','] + +Changes to the Compiler +----------------------- + +A new ASDL expression type ``Starred`` is added which represents a +starred expression. Note that the starred expression element +introduced here is universal and could later be used for other +purposes in non-assignment context, such as the ``yield *iterable`` +proposal. + +The compiler is changed to recognize all cases where a starred +expression is invalid and flag them with syntax errors. + +A new bytecode instruction, ``UNPACK_EX``, is added, whose argument +has the number of mandatory targets before the starred target in the +lower 8 bits and the number of mandatory targets after the starred +target in the upper 8 bits. For unpacking sequences without starred +expressions, the old ``UNPACK_ITERABLE`` opcode is kept. + +Changes to the Bytecode Interpreter +----------------------------------- + +The function ``unpack_iterable()`` in ceval.c is changed to handle +the extended unpacking, via an ``argcntafter`` parameter. In the +``UNPACK_EX`` case, the function will do the following: + +* collect all items for mandatory targets before the starred one +* collect all remaining items from the iterable in a list +* pop items for mandatory targets after the starred one from the list +* push the single items and the resized list on the stack + +Shortcuts for unpacking iterables of known types, such as lists or +tuples, can be added. + + +The current implementation can be found at the SourceForge Patch +tracker [SFPATCH]_. It now includes a minimal test case. Open Issues @@ -98,7 +158,7 @@ Open Issues References ========== -None yet. +.. [SFPATCH] http://python.org/sf/1711529 Copyright