0

I was reading an online document explaining unpacking (*args and **kwargs). Getting confused by the following two asserts, not sure why the second function is invalid. Could anyone help me to understand the reason?

def f(x, y, z):
    return [x, y, z]

t = (3,)  
d = {"z": 4}
assert f(2, *t, **d) == [2, 3, 4]
assert f(x=2, *t, **d) == [2, 3, 4]  # TypeError: f() got multiple values for argument 'x'

Reference https://caisbalderas.com/blog/python-function-unpacking-args-and-kwargs/


Note: This question differs from TypeError: got multiple values for argument because it requires additional knowledge of how argument unpacking works in Python.

insectean
  • 100
  • 1
  • 2
  • 6
r0n9
  • 2,505
  • 1
  • 29
  • 43
  • 1
    This should probably be reopened. There is a pending edit that, while perhaps not appropriate as an edit, *is* correct in stating that the question linked as duplicate doesn't adequately answer *this* question. There may be a canonical answer somewhere else, but the one that was used when this question was closed ain't it. – Z4-tier Nov 24 '22 at 04:54
  • "There is a pending edit that, while perhaps not appropriate as an edit, is correct in stating that the question linked as duplicate doesn't adequately answer this question." I disagree. As far as I can tell, the problem here is the same as in the other question, and it is answered accurately by the answer there. For that matter, the accepted answer here says functionally the same thing as the accepted answer there. – Karl Knechtel Nov 25 '22 at 08:38
  • 2
    @KarlKnechtel this question involves tuple unpacking and automatic reordering of keyword and positional arguments in a way that isn't seen in the other question or its accepted answer. The difference is subtle, but not trivial or immaterial, and these questions are only the same if we ignore that difference. – Z4-tier Nov 27 '22 at 22:40
  • The other question answers "what is allowed?" This question appears to be "why isn't this specific thing allowed?" I'm still not seeing a distinction. – Karl Knechtel Nov 28 '22 at 13:15

1 Answers1

5

You are trying to place a positional argument after a keyword argument. The actual error message is confusing. I am honestly surprised placing tuple unpacking after a keyword is allowed.

It is the similar to doing:

f(x=2, 3, 4)

Which raises a SyntaxError.

I believe the difference is that the tuple unpacking is handled first and shifts keyword arguments to the right. So effectively, you have this equivalency:

f(x=2, *t, **d)

is that same as

f(*t, x=2, **d)

Which is why you are getting TypeError: f() got multiple values for argument 'x'

James
  • 32,991
  • 4
  • 47
  • 70
  • 1
    *"I believe the difference is that the tuple unpacking is handled first ..."* Yes, here's the relevant documentation: https://docs.python.org/3/reference/expressions.html#index-48 – wjandrea Jan 01 '20 at 22:51