569

Suppose I have a function like:

def myfun(a, b, c):
    return (a * 2, b + c, c + b)

Given a tuple some_tuple = (1, "foo", "bar"), how would I use some_tuple to call myfun? This should output the result (2, "foobar", "barfoo").

I know could define myfun so that it accepts the tuple directly, but I want to call the existing myfun.


See also: What do ** (double star/asterisk) and * (star/asterisk) mean in a function call? - the corresponding question for people who encounter the syntax and are confused by it.

0

5 Answers 5

993

myfun(*some_tuple) does exactly what you request. The * operator simply unpacks the tuple (or any iterable) and passes them as the positional arguments to the function. Read more about unpacking arguments.

3
  • 17
    The * operator simply unpacks the tuple and passes them as the positional arguments to the function. See more here: docs.python.org/3/tutorial/…
    – john_mc
    Commented Jun 30, 2017 at 21:09
  • 4
    Note that the same syntax can be used for lists as well as tuples.
    – brendon-ai
    Commented Aug 17, 2017 at 13:22
  • I've found that you can do the same with lists, (in fact, any iterable, including strings), not sure how their mutability affects things. That would be interesting to look into.
    – wcyn
    Commented Nov 26, 2017 at 11:47
81

Note that you can also expand part of argument list:

myfun(1, *("foo", "bar"))
3
  • 18
    It appears you can only do this if the expanded tuple is after the normally-provided arguments - the interpreter doesn't like it when I do this: some_func(*tuple_of_stuff, another_argument)
    – Tom Galvin
    Commented Apr 19, 2015 at 20:46
  • 7
    @Quackmatic Having the expanded tuple in any location seems to work fine in Python 3.5.1
    – River
    Commented Jun 13, 2016 at 13:00
  • 1
    @Quackmatic seconding @River, this works fine in Python 3.5.4: def func(a,b,c,d): print(a,b,c,d) with args = ('fee', 'fi', 'fo'); func(*args, 'fum')
    – R. Navega
    Commented Sep 6, 2018 at 13:25
16

Take a look at the Python tutorial section 4.7.3 and 4.7.4. It talks about passing tuples as arguments.

I would also consider using named parameters (and passing a dictionary) instead of using a tuple and passing a sequence. I find the use of positional arguments to be a bad practice when the positions are not intuitive or there are multiple parameters.

9

This is the functional programming method. It lifts the tuple expansion feature out of syntax sugar:

apply_tuple = lambda f, t: f(*t)

Redefine apply_tuple via curry to save a lot of partial calls in the long run:

from toolz import curry
apply_tuple = curry(apply_tuple)

Example usage:

from operator import add, eq
from toolz import thread_last

thread_last(
    [(1,2), (3,4)],
    (map, apply_tuple(add)),
    list,
    (eq, [3, 7])
)
# Prints 'True'
8
  • 14
    This is not helpful for a beginner. It uses third-party modules and does other confusing stuff...
    – gberger
    Commented May 26, 2017 at 14:09
  • 2
    toolz is third-party, is what I meant
    – gberger
    Commented May 30, 2017 at 8:54
  • 8
    Not every answer has to be for a beginner
    – Jordan
    Commented Sep 2, 2017 at 4:30
  • 1
    For the example you gave, one can use starmap docs.python.org/3.7/library/itertools.html#itertools.starmap
    – Bo.
    Commented Sep 4, 2019 at 11:31
  • 2
    This is a terrible answer Commented May 27, 2020 at 13:33
7

Similar to @Dominykas's answer, this is a decorator that converts multiargument-accepting functions into tuple-accepting functions:

apply_tuple = lambda f: lambda args: f(*args)

Example 1:

def add(a, b):
    return a + b

three = apply_tuple(add)((1, 2))

Example 2:

@apply_tuple
def add(a, b):
    return a + b

three = add((1, 2))
1
  • You can also just define : def add(some_tyuple: tuple) and then access with an index Commented Mar 24, 2021 at 13:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.