FAQ: Introduction to Functions - Multiple Returns

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:

Without a receiver at the caller, it is not possible to access more than one return value in a print statement. Returns are not suspended in memory past their first access. They are consumed.

If there is a yes/no question to this, then, no.

1 Like

Thank you for the answer! :blush:

1 Like

Aside

Consider carefully what you want each function to do. Arbitrarily inserting return values is counterproductive. If a function is meant to return the result of a computation, then let its return be just that, and nothing else.

Under that premise this question would never have come up, although it is good that it did, and now we know.

Treat functions like mathematical equations.

f(x) = some function of x

y = f(some x)

Make them simple and always have a return so the expression they are used in makes sense and evaluates correctly. Don’t write programs inside a function. Write pure, concise algorithms that always have predictable results that are consistent across all inputs.

def mul(a, b):
    return a * b

y = mul(m, n) + o

Done and dusted.


The place to write a program is inside an object, namely a class. It may end up involving several class defined objects, but it is still a class. This form of composing code refines the method library so that they are all associated to a particular (one or other) class, not just functions out in the open namespace. Methods are expected to recognize their respective objects and know how to access their attributes. Functions aren’t that intelligent. They don’t know what we give them unless we tell them.

For example, let’s take multiplication, to continue from above. Python int instances have a __mul__ attribute. When the program sees us multiply two integers, it treats the first as self, and the second as other.

return self.value * other.value

It was the __mul__() method that performed that operation.

>>> a = 6
>>> b = 7
>>> a.__mul__(b)
42
>>> 

That’s the progression when Python sees this…

a * b

Remember, built-ins act upon any object; methods act only upon instance objects.

Multiplication is a method, not a function.


The repeat operator

Python has extended the meaning of * in that if the types don’t match, and the opposing type is a character it will repeat their value N times (N being the number in the expression).

>>> 'O' * 8
'OOOOOOOO'
>>> 
>>> ['O'] * 8
['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O']
>>> [['O' * 8] * 8][0]
['OOOOOOOO', 'OOOOOOOO', 'OOOOOOOO', 'OOOOOOOO', 'OOOOOOOO', 'OOOOOOOO', 'OOOOOOOO', 'OOOOOOOO']
>>> 

Note that in the second example we introduced a list as the containing data structure.

Definitely play with this operator in the sandbox. Learn its behavior. Time well spent, imho.

I got the code correct. However, the console still kept saying that most_popular1 is not defined. It didn’t say anything about the other two variables.