FAQ: Introduction to Functions - Multiple Returns

The function takes no arguments, but returns three values. The three variables in line 6 are the receivers of those values. The returns are assigned in order to those variables.

2 Likes

Hi @tgrtim

This is a really nice answer. Could you please also explain the backworking of the returned values are being assigned to a variable?

I’m slightly lost and out of intuition as to how three variables were put together in one line, and given a value basis the returned value of a function.

Here’s how I imagine it to be: On the right-hand side, the function is called - There’s no argument to it, since it already has defined variables and an output which isn’t dependent on a dynamic input. In an imaginary scenario, python reads it and throws the value out - But how does it then assign the value to the variables so now defined on the left?

What’s working there?

So far, we’ve been only been taught defining variables one by one.

Like,

variabl1 = “Value1”
variable2=“Value2”

Hmm, there’s a couple of things going on there that you may not have been introduced to. Firstly the line return x, y, z is not special to returns (the x, y, z, bit that is), you can do this at any time and what you create is a tuple. This is a very simple sequence type in Python, ordered, immutable and therefore fairly low cost to create. You could equally create the tuple first, my_tup = 1, 2, 3, and then return it.

So you almost cheat the limits on return by still passing a single object (much like you could with a list or other sequence/container type, e.g. mylist = [1, 2, 3,]; return mylist).

The idea of objects may not have been introduced at this point. If Python is your first language then this may be a difficult concept until you hit classes and start creating your own objects so maybe keep it mind for future study. Each integer, list, tuple etc. etc. is a single object (containers can then contain references to other objects).


As for the assignment it’s a special kind of assignment you can perform with some container types. A simple example might be-

x, y, z = 1, 2, 3,

As mentioned above we could get the same assignment result with-

my_tup = 1, 2, 3,
x, y, z = my_tup

You can unpack and assign some containers like this but only if there are an equal number of items in the container as names to assign (the * unpacking operator can change this but I’m not going into it just now).

This can be more readable in some cases but is also less robust (if you have an uneven number of items in the container compared to names then you’ll run into errors). Worth knowing but don’t over-use it.

4 Likes

def top_tourist_locations_italy():
first = “Rome”
second = “Venice”
third = “Florence”
return first, second, third
most_popular1, most_popular2, most_popular3 = top_tourist_locations_italy()

print(most_popular1)
print(most_popular2)
print(most_popular3)

why does my code not work?
the instructions all have checked blue but it’s still not working.

any idea what i did wrong?

Please see How do I format code in my posts? for adding code in the future as the forums remove things like indentation from code which is anathema to whitespace reliant code like Python (it’s just generally easier to read too).

I believe your function call is actually part of the function block at present, that is this line most_popular1, most_popular2, most_popular3 = top_tourist_locations_italy() is not part of the main code block and therefore it’s never called.

Make sure it’s not indented with the function, removing the indent and sticking it with the print statements would be wise.

1 Like

Hey all and @mtf

I’m getting a SyntaxError (can’t assign to function call) on line 7 of code snippet when I assign a function call**()** on the left side of the variables (most_popular1, most_popular2, most_popular3).

Is this because Python (or any programming language) reads code from left to right; therefore, the variables are not seen? I know code is read from top to bottom but I assumed if the function call and variables are on the same line it would work. Any thoughts?

Also, is this recommended or should the lesson be refactored? I would assume its not best practice to create variables for a function call on the global space.

def top_tourist_locations_italy(): first = "Rome" second = "Venice" third = "Florence" return first, second, third top_tourist_locations_italy() = most_popular1, most_popular2, most_popular3 print(most_popular1) print(most_popular2) print(most_popular3)

You’ve just got that assignment inverted, since you want to assign values to most_popular1, most_popular2, most_popular3 they should indeed be on the left of the assignment. So a typical usage of a function might be-

assignment = function_call(args)

For a typical assignment what’s on the left hand side is evaluated first and then it is assigned to the RHS.
Edit: Err sorry, brainfart moment. That should definitely be the other way around, evaluate the RHS, then assign the results to the LHS.

I wouldn’t worry overmuch about best practices during the lessons, many of them are kept simple and don’t concern themselves with best practices and they’re best used for learning syntax.

1 Like

Sounds good. Thank you for the speedy response TigerT.

1 Like

Hi there, there is nothing on the console after preparing the following code:

def top_tourist_locations_italy():

first = “Rome”
second = “Venice”
third = “Florence”

return first, second, third

most_popular1, most_popular2, most_popular3 = top_tourist_locations_italy(first, second, third)

print(most_popular1)
print(most_popular2)
print(most_popular3)

Can you please help? :slight_smile:
Thanks!

It’s quite hard to tell at the moment as your code formatting and indentation gets stripped by the forums, consider a code hosting site or have a read of How do I format code in my posts?.

Is the function separate to the rest of the script or is all indented? An example of the expected shape (note that the indentation defines what code is part of the function)-

def func():
    return 3

print(func())
Out: 3

So I am noticing in the returns topic when we are defining our topic parameters are no longer being used. Leaving the define (): open with nothing.
When I use a return are those values considered scopes?
I am trying to wrap my head around when and when not to use parameters?
If I don’t use parameters then am I automatically to think that this will be a return type code. (I don’t think that thought process is correct though because I can use return with parameters being defined)

A bit confused.

Believe it or not, that is a choice for the designer/author. Parameters are arbitrary local variables that receive data sent by the caller.

Say we want a function to add two numbers. Since the numbers are themselves arbitrary, we want our function to receive any two numbers. We know those two numbers within our function by the names given to our parameters.

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

The call would contain our numeric values…

print (add_ab(6, 7))    #  13  <=  return value

What messes with people’s heads is that we are not describing 6 + 7, but 13. The computer doesn’t see the 6 and 7, but the 13 the function returns.

Scope relates to the environment in which variables and functions are defined. The common term used to describe scope is ‘execution context.’ When we open up the interactive shell, what we write there will be in global context. There is no context above this one. Inside a function we have a new execution context, thus a new scope, what we refer to as local. Variables declared in this context are invisible (inaccessible) to outer scope.

Our call above passes two numbers to the function but cannot see the variables that will refer to them inside the function. a and b are invisible to the caller. What is visible is the return value. Our caller sees 13.

Think of arguments as following a pipeline into the function, and returns as being a pipeline out of the function, directed back to the caller. Above, our print() statement receives the return value and prints 13 to the display. Once the printing is done, that value disappears into the ether.

Should we wish to preserve a return value, then it will be necessary to assign it to a variable in current scope.

c = add_ab(6, 7)

Now c points to the place in memory where the value 13 is stored.

Values are stored in memory in space allocated by the OS. The variables exist in what is called a namespace. Values are not stored there, only the names that refer to them. Each scope is its own namespace. Memory is unrelated to scope since only the variables know where their respective values are stored.

If this is too convoluted to grasp, then ask more questions.

3 Likes

This is a solid answer! I was very confused with the argument being passed to the function parameter.

1 Like

Sorry for the basic question but why is [0] referring to the first position in the sequence? You’d have thought it would be [1] but I’m a newb so please enlighten.

Python indexes start at zero for all objects that can be indexed (subscriptable).

"abcd"[0]                =>  a

['a', 'b', 'c', 'd'][0]  =>  a

('a', 'b', 'c', 'd')[0]  =>  a

An easy way to remember is to think of offset from left edge. The first position has an offset of zero.

I’d like to know if it is possible and if so how to do it, to call each returned value like we can do with lists. Meaning, with lists if we add the index at the end of the list then we get that specific value, I want to know if it is possible to do the same with returned value without putting it in a variable.

I don’t know if what I said makes sense, I hope it did. If not I can explain further on request. Here’s a bit of code I did that achieves the result I’m looking for, but I’d like to know if it can be done the way I asked.

def c_to_f(c_temp): f_temp = c_temp * (9/5) + 32 return c_temp, round(f_temp,1) #This is the part I'd like to know if there's a way to advoid. c0_in_fahrenheit = c_to_f(0) #So instead of storing the returned values in a variable, I'd like to know if I can call each returned value in their respective section of the print here. print(c0_in_fahrenheit[0],"degrees Celsius is",c0_in_fahrenheit[1],"degrees in Fahrenheit\n")

If there are multiple returns then we need to unpack them at the caller. That would necessitate variables. At least one to take the collection.

cf = c_to_f(0)

The return value is a tuple with two values. We can use subscripting to access them,

cf[0]
cf[1]

or we can unpack the tuple into two variables,

c, f = c_to_f(0)
2 Likes

Hey mtf I really appreciate your time, but that doesn’t quite answer my question. I already knew what you replied, that’s not what I asked.

If there are multiple returns and you want to access them without using variables then it would mean multiple calls with the same argument. How can we expect to access the values without a reference object?

1 Like

How can we expect to access the values without a reference object?

I don’t know, that’s why I’m asking. :laughing: