2
x = func(*(xa,) + args)
y = func(*((xc,) + args)) 

where args is an array and function definition is:

def func(lamb, data):
    # statements

I learnt about *args, but I couldn't find the exact difference between these lines.

  • 5
    an extra set of brackets. Thats it, there is no difference in execution, the byte code is identical: `dis.dis("func(*(xa,) + args)")` gives the exact same operations as `dis.dis("func(*((xc,) + args))")` – Tadhg McDonald-Jensen Jun 03 '16 at 07:17
  • 4
    also the first uses `xa` while the second uses `xc` ;) –  Jun 03 '16 at 07:20
  • 1
    If the function you are trying to call takes two arguments and you want to pass it two arguments why are you using the `*args` mechanic at all? Don't you want to just do `func(xa, args)` ? – Tadhg McDonald-Jensen Jun 03 '16 at 07:39
  • I am pretty new to Python. I amn't writing, just trying to understand a source code @TadhgMcDonald-Jensen – Sandeep Veerlapati Jun 03 '16 at 08:16

1 Answers1

5

The only difference is the extra set of brackets and one uses xa while the other uses xc, but even that doesn't make much of a difference to the byte code, take a look:

# python 2 needs to use dis.dis(compile("func(*(xa,)+args)","","eval"))
# to get same result, see http://stackoverflow.com/questions/12673074/how-should-i-understand-the-output-of-dis-dis
>>> dis.dis("func(*(xa,)+args)")
  1           0 LOAD_NAME                0 (func)
              3 LOAD_NAME                1 (xa)
              6 BUILD_TUPLE              1
              9 LOAD_NAME                2 (args)
             12 BINARY_ADD
             13 CALL_FUNCTION_VAR        0 (0 positional, 0 keyword pair)
             16 RETURN_VALUE
>>> dis.dis("func(*((xc,)+args))")
  1           0 LOAD_NAME                0 (func)
              3 LOAD_NAME                1 (xc)
              6 BUILD_TUPLE              1
              9 LOAD_NAME                2 (args)
             12 BINARY_ADD
             13 CALL_FUNCTION_VAR        0 (0 positional, 0 keyword pair)
             16 RETURN_VALUE

This is a simple matter of precedence, the addition takes priority over the * unpacking (CALL_FUNCTION_VAR is the exact bytecode used) so adding brackets doesn't change anything, much like here:

3 * 5 + 1

The multiplication will happen first so adding brackets around it:

(3 * 5) + 1

Doesn't change what is going to happen.


Also note that you don't have to add tuples together when unpacking arguments, you can just as easily do:

func(xa, *args)

to accomplish the same result without having to add tuples together (and this will work when args is something other then a tuple where as your version would raise a TypeError)

Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59