Friday Finking: initialising values and implied tuples

Chris Angelico rosuav at gmail.com
Mon Apr 5 12:52:10 EDT 2021


On Tue, Apr 6, 2021 at 2:32 AM Rob Cliffe via Python-list
<python-list at 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. If there is ANY Python code executed to
calculate those values, it could depend on the previous assignments
being completed.

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.

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


More information about the Python-list mailing list