Chris Angelico <ros...@gmail.com> writes: > On Mon, Sep 2, 2019 at 12:36 PM Alan Bawden <a...@csail.mit.edu> wrote: ... > > > > a,b = 2,3 and [a,b] = [2,3] ... > > It looks to me like they generate identical code. The first one calls the > > construction of a tuple, where the second one calls for the construction of > > a list. It would be surprising if the compiler optimized the tuple > > away, but failed to optimize the list away! > > > > Well, you can find out with the 'dis' module.
Actually, when I wrote "It looks to me", I was in fact looking at the results of calling `dis.dis'! But I had unconciously changed what the OP wrote to make it more realistic. I tested: >>> def f(x, y): x, y = y, x [x, y] = [y, x] >>> dis.dis(f) 2 0 LOAD_FAST 1 (y) 3 LOAD_FAST 0 (x) 6 ROT_TWO 7 STORE_FAST 0 (x) 10 STORE_FAST 1 (y) 3 13 LOAD_FAST 1 (y) 16 LOAD_FAST 0 (x) 19 ROT_TWO 20 STORE_FAST 0 (x) 23 STORE_FAST 1 (y) 26 LOAD_CONST 0 (None) 29 RETURN_VALUE And I observed that whatever peephole optimization got rid of the tuple also got rid of the list. Clearly "BUILD_LIST 2" or "BUILD_TUPLE 2" followed by "UNPACK_SEQUENCE 2" can be replaced by "ROT_TWO", and the compiler knew that! It never occured to me that the case where all the elements of the sequence to the right of the "=" were constants would change that, but yes, you are right about that (but read on...): > >>> def f(): > ... a, b = 2, 3 > ... a, b = [2, 3] > ... > >>> dis.dis(f) > 2 0 LOAD_CONST 1 ((2, 3)) > 2 UNPACK_SEQUENCE 2 > 4 STORE_FAST 0 (a) > 6 STORE_FAST 1 (b) And indeed, if they are all constants, then the tuple itself is a constant, and the obvious peephole optimization is no longer available! But wait... > 3 8 LOAD_CONST 2 (2) > 10 LOAD_CONST 3 (3) > 12 BUILD_LIST 2 > 14 UNPACK_SEQUENCE 2 > 16 STORE_FAST 0 (a) > 18 STORE_FAST 1 (b) Dang! There is exactly the instruction sequence I just argued could be optimized away still sitting right there. So maybe my belief that this is being done by peephole optimization is in fact incorrect? So I went and tried again: bash-4.2$ python3 -E Python 3.6.6 (default, Aug 13 2018, 18:24:23) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> def f(): ... a, b = 2, 3 ... a, b = [2, 3] ... a, b = b, a ... a, b = [b, a] ... >>> import dis >>> dis.dis(f) 2 0 LOAD_CONST 3 ((2, 3)) 2 UNPACK_SEQUENCE 2 4 STORE_FAST 0 (a) 6 STORE_FAST 1 (b) 3 8 LOAD_CONST 1 (2) 10 LOAD_CONST 2 (3) 12 ROT_TWO 14 STORE_FAST 0 (a) 16 STORE_FAST 1 (b) 4 18 LOAD_FAST 1 (b) 20 LOAD_FAST 0 (a) 22 ROT_TWO 24 STORE_FAST 0 (a) 26 STORE_FAST 1 (b) 5 28 LOAD_FAST 1 (b) 30 LOAD_FAST 0 (a) 32 ROT_TWO 34 STORE_FAST 0 (a) 36 STORE_FAST 1 (b) 38 LOAD_CONST 0 (None) 40 RETURN_VALUE OK, now I'm confused. How come I'm not seeing the BUILD_LIST/UNPACK_SEQUENCE sequence that you're seeing? > This is with CPython 3.9. It's entirely possible that other Pythons > and/or other versions of CPython may give different results, but with > this particular interpreter, the list is not optimized away. I actually did try this with several different versions of CPython going back to 2.4 and up to 3.6, and they all behave this way for me. Maybe something changed after 3.6? Weird... -- Alan Bawden -- https://mail.python.org/mailman/listinfo/python-list