a tuple
in python (in a code block) is defined by the commas; the parentheses are not mandatory (in the cases below). so these three are all equivalent:
a, b = 1, 2
a, b = (1, 2)
(a, b) = 1, 2
if i define a function
def f(a, b):
print(a, b)
calling it this way will work:
f(2, 3)
this will not:
f((2, 3))
# TypeError: f() missing 1 required positional argument: 'b'
how does python treat tuples differently when they are function arguments? here the parentheses are necessary (i understand why this is the case and i am happy python works this way!).
my question is: how does python treat tuples differently when they are function arguments.
A tuple can also be passed as a single argument to the function. Individual tuples as arguments are just individual variables. A function call is not an assignment statement; it's a reference mapping.
If a method accepts a tuple as an argument, that means it accepts multiple values. If a method returns a tuple, that means it returns multiple values. As an example, the Invoke() method in BindableFunction accepts a tuple as an argument, meaning it can accept multiple arguments.
The Python tuple() function is a built-in function in Python that can be used to create a tuple. A tuple is an ordered and immutable sequence type.
For convenience, Python constructs a temporary tuple as needed for an assignment statement. Thus, all three of your assignment statements are exactly the same once they reach data movement.
A function call is not an assignment statement; it's a reference mapping. Therefore, the semantics are different.
If you want Python to unpack your tuple into two separate arguments, use the *
operator:
f(*(2, 3))
A tuple behaves like an immutable list. The fact that you notate them with parentheses is perhaps confusing, but it's more or less a coincidence - a result of the fact that parentheses are used for grouping things together and reducing ambiguity otherwise.
When you call a function, you're not providing a tuple. You're providing arguments. A tuple can be an argument, but only one - it's just a variable of type tuple
.
What you can do is expand a tuple (or a list) into a a series of arguments with this notation:
tup = (2, 3)
f(*tup)
# expand the tuple (2,3) into a series of arguments 2, 3
You can do that with dictionaries as well, except with **
instead of *
:
my_dict = {"arg1": 1, "arg2": 2}
f(arg1=my_dict["arg1"], arg2=my_dict["arg2"])
f(**my_dict) # these are equivalent
On the other hand, functions can take arbitrary numbers of arguments (similar to how other languages do for printf()
calls). For example:
def g(*args):
print("I got this many arguments:", len(args))
Here, if you do type(args)
, you get tuple
, and if you do type(*args)
, you get an error. This is because, in function headers, the *
does the exact opposite: it packs the arguments that were given to the function into a single tuple, so that you can work with them. Consider the following:
g(2, 3) # 2 arguments, both integers
g((2, 3)) # 1 argument, a tuple
g(*(2, 3)) # 2 arguments, both integers
In short,
*
and **
operators are able to unpack tuples/lists/dicts into arguments on one end, and pack them on the other endThe thing is that parens are used for several different things in Python -- for calling functions, for making tuples (it's not just the commas that matter, see the empty tuple ()
), for changing evaluation priority in expressions.
In cases where interpreting them is ambiguous (e.g. your example f(2, 3)
could be either a function call with two arguments, or a function call with one argument that is a tuple) the language has to make a choice.
If the Python parser was implemented so that it parsed this as a tuple, it would be impossible to have functions with more than one argument. If the Python parser was implemented so that it parsed this as two arguments, it's impossible to pass a literal tuple without the parens.
Clearly the first is a much bigger limitation, so the second was chosen.
Another example is with tuples with one element -- is (1+2)
an expression yielding the number 3, or a tuple with one element, 3? Here if it was the second, then it would be impossible to use parens for expressing priority in an expression ((3+4)*5
vs 3+(4*5)
). So it was decided to require the comma after the first element for 1-element tuples ((3,)
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With