Friday Finking: initialising values and implied tuples

Rob Cliffe rob.cliffe at btinternet.com
Mon Apr 5 13:18:50 EDT 2021



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 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.
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


More information about the Python-list mailing list