classification
Title: Can assign [] = (), but not () = []
Type: enhancement Stage: resolved
Components: Interpreter Core Versions: Python 3.6
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: martin.panter Nosy List: Cesar.Kawakami, Devin Jeanpierre, Kyle.Buzsaki, Rahul Gupta, amaury.forgeotdarc, berker.peksag, eryksun, ezio.melotti, flying sheep, ionelmc, mark.dickinson, martin.panter, ncoghlan, python-dev, r.david.murray, rhettinger, scoder
Priority: normal Keywords: patch

Created on 2015-01-19 19:05 by Devin Jeanpierre, last changed 2016-06-08 13:36 by python-dev. This issue is now closed.

Files
File name Uploaded Description Edit
issue23275.diff berker.peksag, 2015-04-22 09:05 review
issue23275_v2.diff berker.peksag, 2015-06-13 09:03 review
issue23275_v3.diff berker.peksag, 2016-05-04 12:57 review
issue23275_v4.diff martin.panter, 2016-05-17 10:55 review
Messages (31)
msg234324 - (view) Author: Devin Jeanpierre (Devin Jeanpierre) * Date: 2015-01-19 19:05
>>> [] = ()
>>> () = []
  File "<stdin>", line 1
SyntaxError: can't assign to ()

This contradicts the assignment grammar, which would make both illegal: https://docs.python.org/3/reference/simple_stmts.html#assignment-statements
msg234325 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-01-19 19:22
My guess is that it is not worth complicating the parser in order to make these two cases consistent, and it should be treated as a doc error.  We'll see what other developers think.
msg234326 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2015-01-19 20:12
The starting point is recognizing that this has been around for very long time and is harmless.
msg234361 - (view) Author: Kyle Buzsaki (Kyle.Buzsaki) Date: 2015-01-20 09:25
It seems that assigning to [] is the odd one out in this case. Why is this even possible?

>>> [] = ()
>>> [] = {}
>>> [] = set()
>>> list() = ()
  File "<stdin>", line 1
SyntaxError: can't assign to function call
>>> () = []
  File "<stdin>", line 1
SyntaxError: can't assign to ()
>>> {} = []
  File "<stdin>", line 1
SyntaxError: can't assign to literal
>>> set() = []
  File "<stdin>", line 1
SyntaxError: can't assign to function call
>>>
msg234364 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2015-01-20 09:40
But () is the odd one out if you consider

>>> [a, b] = range(2)
>>> [] = range(0)
>>> (a, b) = range(2)
>>> () = range(0)
  File "<stdin>", line 1
SyntaxError: can't assign to ()
msg234365 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2015-01-20 10:19
In ast.c, set_context checks for assignment to an empty tuple, but not an empty list.

        case List_kind:
            e->v.List.ctx = ctx;
            s = e->v.List.elts;
            break;
        case Tuple_kind:
            if (asdl_seq_LEN(e->v.Tuple.elts))  {
                e->v.Tuple.ctx = ctx;
                s = e->v.Tuple.elts;
            }
            else {
                expr_name = "()";
            }
            break;

https://hg.python.org/cpython/file/ab2c023a9432/Python/ast.c#l912
msg241473 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2015-04-19 02:47
As Raymond notes, this is a fairly harmless quirk - it changes a SyntaxError to an iterable length dependent ValueError:

>>> () = []
  File "<stdin>", line 1
SyntaxError: can't assign to ()
>>> [] = ()
>>> [] = [1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 0)

I only found out about this after being puzzled when a typo in a live demo at PyCon 2015 failed to fail as I expected after seeing the presenter type a "[]" into the LHS of an assignment instead of the intended "_".

Removing the data dependence to make the assignment fail immediately (even if never tested against a non-empty iterable) would involve making the handling of List_kind match that of Tuple_kind in the switch statement that eryksun quoted.

I don't think it's an urgent fix, but if someone wanted to fix it (including a new test), I think it would be a reasonable contribution to accept.
msg241474 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2015-04-19 03:34
I would prefer this be fixed in the opposite direction, to allow “unpacking” an empty iterable using round brackets. I have used this syntax on purpose as a concise way to ensure that a generator is exhaused with no more yields:

>>> def gen():
...     yield "partial computation"
...     print("computation allowed to complete")
... 
>>> g = gen()
>>> next(g)
'partial computation'
>>> [] = g
computation allowed to complete
msg241523 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-04-19 17:57
There is also no reason to break currently working code, which turning this into a syntax error would od.
msg241673 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2015-04-20 18:28
> There is also no reason to break currently working code

Agreed.  To take one example, David Beazley's PyCon 2015 talk would have been broken by the suggested change!  (See https://www.youtube.com/watch?v=MCs5OvhV9S4, at around the 42:17 mark.)

If there's any code change resulting from this issue, I also think it should be to make assignment to `()` legal.
msg241790 - (view) Author: Berker Peksag (berker.peksag) * (Python committer) Date: 2015-04-22 09:05
I don't have a strong opinion on this, but here is a patch to make () = [] a valid assignment.
msg241792 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2015-04-22 09:42
About the patch: I'm sure there are other tests to change,
in test_syntax.py for example::

    It's a syntax error to assign to the empty tuple.  Why isn't it an
    error to assign to the empty list?  It will always raise some error  at
    runtime.

    >>> () = 1
    Traceback (most recent call last):
      File "<doctest test.test_syntax[3]>", line 1
    SyntaxError: can't assign to ()
msg244157 - (view) Author: Rahul Gupta (Rahul Gupta) Date: 2015-05-27 12:28
isn't it logical?

[] is a mutable data structure
while () is a immutable data structure

(b, a) = [1, 2] is fine because a and b are mutable
msg244159 - (view) Author: Devin Jeanpierre (Devin Jeanpierre) * Date: 2015-05-27 12:42
[a, b] = (1, 2) is also fine.
msg244161 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2015-05-27 12:53
I prefer to unpack into square brackets in general because it is a mnemonic for the star argument being a list:

>>> (a, *b) = range(3)
>>> a
0
>>> b  # A list, even though it was unpacked using tuple-like syntax
[1, 2]
msg244208 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2015-05-27 17:47
Berker's patch looks good.
It has several virtues:

* the error message is reasonable and clear
* it makes the language more consistent
* it doesn't break any existing code.
* it makes the AST a little simpler and faster
  by removing a special case

The patch needs to updated:
* remove the whatsnew entry
* fix test_codeop which expects "del ()" to raise SyntaxError
* fix test_syntax which fails on "() = 1" and "del ()"
* fix test_with which fails on "with mock as ()"
msg244215 - (view) Author: (flying sheep) * Date: 2015-05-27 19:43
> isn't it logical?
> 
> [] is a mutable data structure
> while () is a immutable data structure

but you don’t assign to data structures, but to names. you *modify* data structures. and in the square bracket assignment syntax you don’t modify the list created by the []. in fact the [] never even create a list.

—————————————————————————————

also it’s news to me that [a, b] = range(2) works!

i always did a, b = range(2), and knew that (a, b) = range(2) works.

but assigning to something looking like a list literal is new and surprising to me. (and i thought i’ve mastered every corner of python’s syntax)
msg244227 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2015-05-28 00:15
+1 for Martin's suggestion of removing the inconsistency the other way (i.e. allowing "() = iterable" to mean the same thing as "[] = iterable", effectively asserting that an iterable is empty)

I also agree with Raymond that it doesn't need to be mentioned in the What's New doc, just in the NEWS file.
msg245308 - (view) Author: Berker Peksag (berker.peksag) * (Python committer) Date: 2015-06-13 09:03
Thanks for the reviews. Here is an updated patch.
msg246382 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2015-07-06 23:20
I welcome this patch to go ahead. But the documentation <https://docs.python.org/3.6/reference/simple_stmts.html#assignment-statements> also needs updating (see original post). I think it should mention that “target_list” can be empty. And it should use “iterable” instead of “sequence” in more places.
msg264223 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2016-04-26 07:15
Martin, do you want to take it from here?
msg264226 - (view) Author: Berker Peksag (berker.peksag) * (Python committer) Date: 2016-04-26 07:40
I missed Martin's comment about the documentation. I will update my patch.
msg264249 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2016-04-26 11:23
Okay I’ll let Berker update his patch, but I’m happy to try my hand at updating the documentation if needed.

I reviewed the current patch. I can’t say whether the ast.c change is good or not. But IMO the test would be better off in somewhere like /Lib/test/test_unpack.py. It is only a superficial relationship with tuples because the syntax looks the same. Also may be worth testing that [] = [] etc work as well.
msg264811 - (view) Author: Berker Peksag (berker.peksag) * (Python committer) Date: 2016-05-04 12:57
Here is an updated patch. I moved the test into test_unpack and added additional tests. sequence -> iterable changes should probably be applied to 3.5 as well.

Thanks for the review, Martin.
msg265108 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2016-05-08 03:10
Erm, I think you went overboard with the sequence → iterable changes and subscripting; see the review. Also, I think target_list should be made optional in the grammar description.
msg265764 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2016-05-17 10:55
Hi Berker. I updated your patch according to my comments in the documentation. I hope you don’t mind.

I reverted all the changes about subscripting and slicing an iterable, since this bug is only about assigning to a “target list”.

Actually it is true (despite the current documentation) that you can often assign

sequence[slice] = iterable

But I think that is a separate problem.
msg265809 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2016-05-18 05:44
New changeset 8a0754fed986 by Berker Peksag in branch 'default':
Issue #23275: Allow () = iterable assignment syntax
https://hg.python.org/cpython/rev/8a0754fed986
msg265811 - (view) Author: Berker Peksag (berker.peksag) * (Python committer) Date: 2016-05-18 05:48
Thanks Martin. Your edits look much better! :) I will be travelling for PyCon US later this week so I just committed issue23275_v4.diff with minor edits.
msg265816 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2016-05-18 07:19
New changeset d3a75daf61e1 by Martin Panter in branch 'default':
Issue #23275: Don’t think this made it into alpha 1
https://hg.python.org/cpython/rev/d3a75daf61e1
msg265817 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2016-05-18 07:22
I just moved the NEWS entry under the alpha 2 heading.

For patches I am going to commit myself, I usually write the NEWS beforehand and remember to adjust it when committing. But perhaps I shouldn’t have done that in this case :)
msg267847 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2016-06-08 13:36
New changeset 39a72018dd76 by Martin Panter in branch '3.5':
Issue #23275: Backport target list assignment documentation fixes
https://hg.python.org/cpython/rev/39a72018dd76

New changeset 8700f4d09b28 by Martin Panter in branch '2.7':
Issue #23275: Backport empty square bracket assignment documentation fix
https://hg.python.org/cpython/rev/8700f4d09b28
History
Date User Action Args
2016-06-08 13:36:22python-devsetmessages: + msg267847
2016-05-18 07:22:20martin.pantersetmessages: + msg265817
2016-05-18 07:19:57python-devsetmessages: + msg265816
2016-05-18 05:48:24berker.peksagsetstatus: open -> closed
resolution: fixed
messages: + msg265811

stage: patch review -> resolved
2016-05-18 05:44:23python-devsetnosy: + python-dev
messages: + msg265809
2016-05-17 10:55:19martin.pantersetfiles: + issue23275_v4.diff

messages: + msg265764
2016-05-08 03:10:30martin.pantersetmessages: + msg265108
2016-05-04 12:57:56berker.peksagsetfiles: + issue23275_v3.diff
type: behavior -> enhancement
messages: + msg264811
2016-04-26 11:23:17martin.pantersetmessages: + msg264249
2016-04-26 07:40:11berker.peksagsetmessages: + msg264226
2016-04-26 07:15:49rhettingersetassignee: rhettinger -> martin.panter
messages: + msg264223
2015-07-06 23:20:30martin.pantersetmessages: + msg246382
2015-06-13 09:03:46berker.peksagsetfiles: + issue23275_v2.diff

messages: + msg245308
2015-05-28 03:45:09scodersetnosy: + scoder
2015-05-28 00:15:18ncoghlansetmessages: + msg244227
2015-05-27 19:43:45flying sheepsetnosy: + flying sheep
messages: + msg244215
2015-05-27 17:47:39rhettingersetassignee: rhettinger
messages: + msg244208
versions: + Python 3.6, - Python 3.5
2015-05-27 12:53:23martin.pantersetmessages: + msg244161
2015-05-27 12:42:47Devin Jeanpierresetmessages: + msg244159
2015-05-27 12:28:34Rahul Guptasetnosy: + Rahul Gupta
messages: + msg244157
2015-05-27 12:08:20ionelmcsetnosy: + ionelmc
2015-04-22 09:42:01amaury.forgeotdarcsetnosy: + amaury.forgeotdarc
messages: + msg241792
2015-04-22 09:05:59berker.peksagsetfiles: + issue23275.diff

versions: + Python 3.5
keywords: + patch
nosy: + berker.peksag

messages: + msg241790
stage: patch review
2015-04-20 18:28:23mark.dickinsonsetnosy: + mark.dickinson
messages: + msg241673
2015-04-19 17:57:04r.david.murraysetmessages: + msg241523
2015-04-19 03:34:31martin.pantersetmessages: + msg241474
2015-04-19 02:47:53ncoghlansetnosy: + ncoghlan
messages: + msg241473
2015-03-02 08:14:16ezio.melottisetnosy: + ezio.melotti
2015-01-20 10:19:31eryksunsetnosy: + eryksun
messages: + msg234365
2015-01-20 09:40:47martin.pantersetnosy: + martin.panter
messages: + msg234364
2015-01-20 09:25:19Kyle.Buzsakisetnosy: + Kyle.Buzsaki
messages: + msg234361
2015-01-19 20:12:04rhettingersetnosy: + rhettinger
messages: + msg234326
2015-01-19 19:22:23r.david.murraysetnosy: + r.david.murray
messages: + msg234325
2015-01-19 19:16:58Cesar.Kawakamisetnosy: + Cesar.Kawakami
2015-01-19 19:05:47Devin Jeanpierrecreate