Why does Python think this is a tuple?

Viewed 152
def my_function(fname):
    print(fname + " Refsnes")

my_function("Emil")
my_function("Tobias")
my_function("Linus")

def my_greeting(*fname):
    print(fname + " Smith")

my_greeting("Don")

The first part runs fine the second part crashes. Here are the results.

Emil Refsnes
Tobias Refsnes
Linus Refsnes

Traceback (most recent call last):
  File "C:/Data/Python/turtleFun/kikiFunction.py", line 19, in <module>
    my_greeting("Don")
  File "C:/Data/Python/turtleFun/kikiFunction.py", line 17, in my_greeting
    print(fname + " Smith")
 TypeError: can only concatenate tuple (not "str") to tuple

I haven't created a tuple, I'm not trying to concatenate. The structures are the same but one runs and the other crashes. Why does Python 3.8.3 think I have a tuple? How do I fix? Tuples would be

myTuple = ("Don", "Fred", "George", "Paul", "John", "Ringo")
1 Answers

Problem

The * next to *fname makes fname a tuple, always.

Understanding what's going on

Let's see what a function with *fname as a parameter really does.

>>> def func(*fnames):
...     print(fnames)
...     print(type(fnames))
>>> func('str 1', 'str 2')
('str 1', 'str 2')
<class 'tuple'>

Look at that! Even though it seems like func takes just 1 parameter (*fnames) we don't get an error even though when we call it with 2 parameters ('str 1' and 'str 2'). That's because the * in *fnames lets any number of parameters (including 0!) to be passed to func, and all of those parameters get passed in as 1 tuple.

This is why, even when you pass just 1 argument to the function, fnames still takes on the type of tuple. In your example:

def my_greeting(*fname):
    print(fname)  # let's not concatenate for now

my_greeting('Don')  # prints a tuple: ('Don',)

Why doesn't Python only use tuples when *fnames is given 2+ args?

Python always uses tuples for *-type arguments so that our code can always expect a certain type. Otherwise, my_greeting('Don') would set fnames to a str, while my_greeting('Don', 'Don2') would set fnames to a tuple of str.

I hope this helps you learn!

Related