This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author terry.reedy
Recipients Joshua.Landau, NeilGirdhar, SilentGhost, gvanrossum, iritkatriel, r.david.murray, terry.reedy
Date 2021-06-16.17:24:01
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1623864241.99.0.366129759764.issue23316@roundup.psfhosted.org>
In-reply-to
Content
The particular example of left-to-right function evaluation in
https://docs.python.org/3/reference/expressions.html#evaluation-order
is "expr1(expr2, expr3, *expr4, **expr5)".

Joshua's claim, without evidence, that "'f(*a(), b=b())' will evaluate b() before a()" was false, as shown by Neil with dis and is now, as shown by Irit with a code example.

But Neil also showed, again with dis, that a revised discrepancy claim, ""'f(b=b(), *a())' will evaluate a() before b()", is true, because reversing the order of these particular arguments does not reverse the evaluation order.  The dis today is equivalent to the one 7 years ago, with CALL_FUNCTION_VAR expanded to two operations.

dis.dis('f(b=b(), *a())')
  1           0 LOAD_NAME                0 (f)
              2 LOAD_NAME                1 (a)
              4 CALL_FUNCTION            0
              6 LOAD_CONST               0 ('b')
              8 LOAD_NAME                2 (b)
             10 CALL_FUNCTION            0
             12 BUILD_MAP                1
             14 CALL_FUNCTION_EX         1
             16 RETURN_VALUE

Irit's example, carried one step further confirms this.

>>> f(b=b(), *a())
a
b
f

Although I considered SilentGhost's reading of
https://docs.python.org/3/reference/expressions.html#calls
as too 'loose' (evaluation order of function argument *is* defined in general), that section address this exact case.

"A consequence of this is that although the *expression syntax may appear after explicit keyword arguments, it is processed before the keyword arguments ..."

I read this as an acknowledgement that this order violates the general rule.

I do wonder whether exception is specific to using a stack machine and implementation convenience or whether *all* implementations must follow this order.  If C-Python specific, it should be labelled as such.

The doc continues with an example call, for a different 'f', where, unlike Irit's 'f', the result is "TypeError: f() got multiple values for keyword argument 'a'".  It concludes "It is unusual for both keyword arguments and the *expression syntax to be used in the same call, so in practice this confusion does not arise."

The problem with mixing unpacking and named values might be even clearer if "f(b=1, *(2,1))" were added to the example box.  Perhaps *exp after x=exp should be prohibited.

If the exception is not removed from the implementation, then perhaps it should be added to the evaluation order section.  Something like

"The one exception is in function calls with *expression after a keyword argument: f(x=expr2, *expr1)."
History
Date User Action Args
2021-06-16 17:24:02terry.reedysetrecipients: + terry.reedy, gvanrossum, r.david.murray, SilentGhost, Joshua.Landau, NeilGirdhar, iritkatriel
2021-06-16 17:24:01terry.reedysetmessageid: <1623864241.99.0.366129759764.issue23316@roundup.psfhosted.org>
2021-06-16 17:24:01terry.reedylinkissue23316 messages
2021-06-16 17:24:01terry.reedycreate