On 05/04/2021 17:52, Chris Angelico wrote:
On Tue, Apr 6, 2021 at 2:32 AM Rob Cliffe via Python-list
<python-list@python.org> wrote:


It doesn't appear to, at least not always.  In Python 3.8.3:
from dis import dis
def f(): x = 1 ; y = 2
def g(): (x,y) = (1,2)
dis(f)
dis(g)

Output:
    2           0 LOAD_CONST               1 (1)
                2 STORE_FAST               0 (x)
                4 LOAD_CONST               2 (2)
                6 STORE_FAST               1 (y)
                8 LOAD_CONST               0 (None)
               10 RETURN_VALUE
    3           0 LOAD_CONST               1 ((1, 2))
                2 UNPACK_SEQUENCE          2
                4 STORE_FAST               0 (x)
                6 STORE_FAST               1 (y)
                8 LOAD_CONST               0 (None)
               10 RETURN_VALUE
Thinking some more about this, this (removing the tuples) is not a
straightforward optimisation to do.
It's important to be aware of the semantics here. Saying "x = 1; y =
2" requires that x be set before 2 is calculated (imagine if it had
been "y = x + 2" or something), whereas "x, y = 1, 2" has to do the
opposite, fully evaluating the right hand side before doing any of the
assignments.

I guess it's safe if the RHS is a tuple containing only
      constants, by which I think I mean number/string literals and
built-in constants (None, True etc.).
      variables (NOT expressions containing variables such as "z+1")
which do not occur on the LHS
      tuple/list/dictionary/set displays which themselves contain only
the above, or nested displays which themselves ... etc.
Nope, there's no "it's safe if" other than constants - which are
already handled differently.
How are constants handled differently (apart from using LOAD_CONST)?  See my dis example above.
  If there is ANY Python code executed to
calculate those values, it could depend on the previous assignments
being completed.
I don't understand.  What semantic difference could there be between
    x = { 1: 2 }    ;    y = [3, 4]   ;   z = (5, 6)
and
    x, y, z = { 1:2 }, [3, 4], (5, 6)
?  Why is it not safe to convert the latter to the former?
But I withdraw "set" from my "safe" list because I now realise that "set" could be reassigned.

But the tuples aren't a problem here. They're a highly optimized way
of grabbing multiple things at once. In the "x, y = 1, 2" case, the
compiler would be free to implement it as "LOAD_CONST 1, LOAD_CONST 2,
ROT_TWO, STORE_FAST x, STORE_FAST y" (equivalent to what you'd see for
"x, y = y, x"), but it doesn't, so we can fairly confidently expect
that the tuple is faster.
Not according to the Windows timings I mentioned in my previous post.

BTW, if you want to play around with CPython's optimizations, there's
another case to consider:

def f(): x = y = 1
   1           0 LOAD_CONST               1 (1)
               2 DUP_TOP
               4 STORE_FAST               0 (x)
               6 STORE_FAST               1 (y)

The constant gets loaded once (which is semantically important), and
then duplicated on the stack, leaving two available for storing. Feel
free to play around with different combinations here. For instance,
"x, y = a, b = 1, 2" should now be unsurprising, but perhaps there'll
be some more complicated examples that are interesting to explore.

I love dis stuff. :)

ChrisA
Best wishes
Rob Cliffe
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to