Can You Actually Return Multiple Values From a Function in Python?

Can You Actually Return Multiple Values From a Function in Python? Featured Image

As we head into summer, I’ve found some extra time to do some writing. As a result, I’ve had some space to talk about some topics that have been on my mind recently. For instance, a saw a tweet recently claiming that you can return multiple values from a function in Python. But, can you really do that? That’s the topic of today’s piece.

Table of Contents

Tech Twitter Inspiration

I recently got the inspiration to write this post after seeing the following tweet floating around.

In case this tweet gets deleted, the gist is that “the machine learning guy,” Santiago, shared a tweet that claimed that you could return multiple values from a function in Python. Here’s his example:

def operations(x, y):
  return x + y, x * y

result1, result2 = operations(4, 4)
print(result1, result2)
# 8 16

When I saw it, my first thought was: “well, you can’t actually return multiple values from a function in Python.” Then, I realized how much of a pedantic snob I sounded like, so I didn’t bother commenting. After all, I don’t think the intent of Santiago’s post is to spread misinformation. In fact, if you search “return multiple values python” on Google, you’ll get several solutions that resemble what Santiago shared.

That said, I love to teach, so I thought this would be a great opportunity to take this awesome snippet from Santiago and try to add some context to it. Without further ado, let’s dive in!

How Functions Work

In the most generic terms possible, Python functions take input and produce output. Sometimes, we try to use different terminology when we want to be more specific about what a function is doing. For example, a strict definition for a function would be a unit of code that takes input and produces output without side effects. Side effects in this case being any modifications to the inputs that persist after execution of the function. In contrast to this would be a procedure which takes input and modifies it without output.

That said, I don’t really intend to get into all sorts of function-related jargon. If you’re interested in that sort of thing, you can check out my post on the differences between functions and procedures. Instead, I want to talk a bit about how functions work more broadly.

To start, let’s revisit Santiago’s example:

def operations(x, y):
  return x + y, x * y

Here, Santiago defines a function called “operations.” The idea behind this function is pretty straightforward: by providing two numbers, you can get the result of the addition and multiplication of those numbers at the same time.

Now, Python can be a bit frustrating because we have no idea what types of variables `x` and `y` are supposed to be. I only knew it was meant to accept numbers because of the example that Santiago provided, but there may be other valid inputs. For example, I know that it is possible to scale a list using an integer, and it’s also possible to append two lists. That said, I can’t think of an example off the top of my head that would work for a pair of inputs. If I can come up with something, I’ll update this post. That said, just know that programs will often crash with a TypeError if types aren’t as expected.

Regardless, assuming we provide proper inputs, the two expressions are then evaluated. For instance, if we call `operations(10, 2)`py, we can expect the addition expression to evaluate to 12 and the multiplication expression to evaluate to 20. After that, the result is returned to the user.

Of course, the question then becomes: what does the returned result look like? We’ll take a look in the next section.

Function Return Values

Python is a bit wacky in the types of values a function can return. In other words, because functions have no return types, they can return anything. In fact, a single function doesn’t even have to be consistent in the types of values it returns:

def generate_chaos(x):
  if x == 0:
    return "Hola"
  elif x > 0:
    return 7
  else:
    return [2, 4, 6, 8]

However, functions must return something—even if that something is implicitly nothing (`None`py). That said, while we must return something, it can only be one thing.

But wait a minute? Clearly, Santiago is returning more than one thing, right? Take a peek at his solution again:

def operations(x, y):
  return x + y, x * y

result1, result2 = operations(4, 4)
print(result1, result2)
# 8 16

It appears that this comma is somehow providing two outputs, and we have to use that same comma to save the two outputs.

In reality, there’s a bit of magic happening here behind the scenes. There are two concepts at play that make the multiple return values possible. First, when we place a comma between values, we create a tuple (i.e., an immutable list):

>>> 2, 3
(2, 3)
>>> 17, 5, 2
(17, 5, 2)

Naturally, we can take advantage of this syntax to package up values as that one thing we need to return. We can see how this works by calling our function on the command line:

>>> operations(3, 5)
(8, 15)
>>> operations(9, 5)
(14, 45)

In other words, if we were to call this function, the returned result would be a tuple—not two distinct values.

This leads us to our second question. How are we then able to separate the tuple into individual variables? That’s done through a concept known as destructuring or unpacking. In the simple case, we’re basically using that same tuple syntax to create two new homes for our two values. You can probably imagine how this would look if we increased the number of operations returned:

def operations(x, y):
  return x + y, x * y, x ** y

addition, multiplication, power = operations(4, 4)

The cool thing about destructuring is that we can trash values that we don’t care about:

addition, *_ = operations(10, 11)

Here, we store the addition result in its own variable, and we dump the other two values into a temporary variable using the asterisk. The result looks like this:

>>> addition, *_ = operations(10, 11)
>>> _
[110, 100000000000]
>>> addition
21

Now, you can see that our function isn’t really returning three values but rather one list of three values. We can then process that list as needed.

Is It Possible to Return Multiple Values in Python?

So, now that we’ve gone over some of the underlying concepts surrounding functions and their return values, how are you feeling? Do you think it’s possible to return multiple values from a function in Python? I would argue that it’s not, but I can see why folks might say otherwise. It’s just a little weird considering that this can be accomplished in just about any other language that has lists. For example, would you say that you’re returning multiple values in this Java example?

public static int[] operations(int x, int y) {
    return new int[] {x + y, x * y};
}

Perhaps because Python does not have static typing, people might feel more inclined to argue that Python functions can return multiple values. Do these type hints change your mind?

def operations(x: int, y: int) -> tuple[int, int]:
  return x + y, x * y

If not, no worries! I’m not here to tell folks how to think—just here to provide another perspective. That said, I took some time to dig through the comments to see if anyone had a similar critique as me, and there were a few. Interestingly, Santiago didn’t really care for the pedantry.

As an educator, I don’t love this response. Surely, it’s important that people understand what’s actually happening, right? If they just follow the idiom, they probably won’t run into issues, but it does feel a bit misleading regardless.

All that said, I’m not trying to diss Santiago. I love his content, and he’s done a lot for eliminating gatekeeping in the community. As you probably know, I’ve spent a fair bit of my time complaining about gatekeeping in tech, and I think Santiago has done a lot to ensure the community is accepting of as many people as possible. Hopefully, this little post doesn’t get me on his bad side! Just thought this would be a great teaching opportunity.

As always, if you like this article, I’d encourage you to stick around. You can find relevant articles below. Alternatively, you can show your support by checking out my article on how to grow the community. Otherwise, thanks for stopping by! Take care.

Jeremy Grifski

Jeremy grew up in a small town where he enjoyed playing soccer and video games, practicing taekwondo, and trading Pokémon cards. Once out of the nest, he pursued a Bachelors in Computer Engineering with a minor in Game Design. After college, he spent about two years writing software for a major engineering company. Then, he earned a master's in Computer Science and Engineering. Today, he pursues a PhD in Engineering Education in order to ultimately land a teaching gig. In his spare time, Jeremy enjoys spending time with his wife, playing Overwatch and Phantasy Star Online 2, practicing trombone, watching Penguins hockey, and traveling the world.

Recent Posts