Expanding tuples into arguments
Asked Answered
U

5

564

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.

Ultun answered 3/1, 2010 at 2:22 Comment(0)
S
984

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.

Supplicant answered 3/1, 2010 at 2:24 Comment(3)
The * operator simply unpacks the tuple and passes them as the positional arguments to the function. See more here: docs.python.org/3/tutorial/…Linguistics
Note that the same syntax can be used for lists as well as tuples.Ananthous
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.Spoilsman
K
80

Note that you can also expand part of argument list:

myfun(1, *("foo", "bar"))
Kike answered 19/3, 2015 at 6:31 Comment(3)
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)Hanseatic
@Quackmatic Having the expanded tuple in any location seems to work fine in Python 3.5.1Woolpack
@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')Deboer
Z
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.

Zarate answered 3/1, 2010 at 2:28 Comment(0)
S
8

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'
Saloon answered 7/1, 2017 at 21:55 Comment(8)
This is not helpful for a beginner. It uses third-party modules and does other confusing stuff...Borries
gberger, lambda f, t: f(*t) does not use third-party modules and I am a Python beginner and this is helpful to me. This is a pure functional approach. If you don't use this style then this answer is not for you.Saloon
toolz is third-party, is what I meantBorries
Not every answer has to be for a beginnerMax
@Borries I'm here because I was curious about a functional approach. :DThymic
For the example you gave, one can use starmap docs.python.org/3.7/library/itertools.html#itertools.starmapSawfish
This is a terrible answerBriefing
An alternative definition with currying done by hand: apply_tuple = lambda f: lambda args: f(*args)Thymic
T
6

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))
Thymic answered 20/11, 2020 at 0:53 Comment(1)
You can also just define : def add(some_tyuple: tuple) and then access with an indexDebbradebby

© 2022 - 2024 — McMap. All rights reserved.