1147

The canonical way to return multiple values in languages that support it is often tupling.

Option: Using a tuple

Consider this trivial example:

def f(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return (y0, y1, y2)

However, this quickly gets problematic as the number of values returned increases. What if you want to return four or five values? Sure, you could keep tupling them, but it gets easy to forget which value is where. It's also rather ugly to unpack them wherever you want to receive them.

Option: Using a dictionary

The next logical step seems to be to introduce some sort of 'record notation'. In Python, the obvious way to do this is by means of a dict.

Consider the following:

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0': y0, 'y1': y1 ,'y2': y2}

(Just to be clear, y0, y1, and y2 are just meant as abstract identifiers. As pointed out, in practice you'd use meaningful identifiers.)

Now, we have a mechanism whereby we can project out a particular member of the returned object. For example,

result['y0']

Option: Using a class

However, there is another option. We could instead return a specialized structure. I've framed this in the context of Python, but I'm sure it applies to other languages as well. Indeed, if you were working in C this might very well be your only option. Here goes:

class ReturnValue:
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return ReturnValue(y0, y1, y2)

In Python the previous two are perhaps very similar in terms of plumbing - after all { y0, y1, y2 } just end up being entries in the internal __dict__ of the ReturnValue.

There is one additional feature provided by Python though for tiny objects, the __slots__ attribute. The class could be expressed as:

class ReturnValue(object):
  __slots__ = ["y0", "y1", "y2"]
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

From the Python Reference Manual:

The __slots__ declaration takes a sequence of instance variables and reserves just enough space in each instance to hold a value for each variable. Space is saved because __dict__ is not created for each instance.

Option: Using a dataclass (Python 3.7+)

Using Python 3.7's new dataclasses, return a class with automatically added special methods, typing and other useful tools:

@dataclass
class Returnvalue:
    y0: int
    y1: float
    y3: int

def total_cost(x):
    y0 = x + 1
    y1 = x * 3
    y2 = y0 ** y3
    return ReturnValue(y0, y1, y2)

Option: Using a list

Another suggestion which I'd overlooked comes from Bill the Lizard:

def h(x):
  result = [x + 1]
  result.append(x * 3)
  result.append(y0 ** y3)
  return result

This is my least favorite method though. I suppose I'm tainted by exposure to Haskell, but the idea of mixed-type lists has always felt uncomfortable to me. In this particular example the list is -not- mixed type, but it conceivably could be.

A list used in this way really doesn't gain anything with respect to the tuple as far as I can tell. The only real difference between lists and tuples in Python is that lists are mutable, whereas tuples are not.

I personally tend to carry over the conventions from functional programming: use lists for any number of elements of the same type, and tuples for a fixed number of elements of predetermined types.

Question

After the lengthy preamble, comes the inevitable question. Which method (do you think) is best?

martineau
  • 99,260
  • 22
  • 139
  • 249
saffsd
  • 21,564
  • 16
  • 57
  • 65
  • 10
    In you excellent examples you use variable `y3`, but unless y3 is declared global, this would yield `NameError: global name 'y3' is not defined` perhaps just use `3`? – hetepeperfan Dec 19 '13 at 14:49
  • 20
    Many great questions with great answers are closed because the 'opinion' keyword arises. You could argue the whole of SO is based on opinion, but it's opinion informed by facts, references and specific expertise. Just because someone asks "which do you think is best" doesn't mean they're asking for personal opinions abstracted from real world facts, references and specific expertise. They are almost certainly asking for precisely that kind of opinion, the kind based thoroughly on, and documented with, the facts, references and specific expertise that the person used to form the opinion. – NeilG Aug 08 '19 at 05:31
  • @hetepeperfan no need to change 3, and neither is defining y3 in global, you could also use a local name ```y3```, that will do the same job too. – okie Oct 27 '19 at 23:31

14 Answers14

662

Named tuples were added in 2.6 for this purpose. Also see os.stat for a similar builtin example.

>>> import collections
>>> Point = collections.namedtuple('Point', ['x', 'y'])
>>> p = Point(1, y=2)
>>> p.x, p.y
1 2
>>> p[0], p[1]
1 2

In recent versions of Python 3 (3.6+, I think), the new typing library got the NamedTuple class to make named tuples easier to create and more powerful. Inheriting from typing.NamedTuple lets you use docstrings, default values, and type annotations.

Example (From the docs):

class Employee(NamedTuple):  # inherit from typing.NamedTuple
    name: str
    id: int = 3  # default value

employee = Employee('Guido')
assert employee.id == 3
ShadowRanger
  • 108,619
  • 9
  • 124
  • 184
A. Coady
  • 44,841
  • 8
  • 28
  • 36
  • 75
    This is only correct answer because it is the only canonical structure that the OP did not consider and because it addresses his problem of managing long tuples. Should be marked as accepted. – airstrike Jul 19 '14 at 22:35
  • 7
    Well, the design rationale for [``namedtuple``](https://docs.python.org/3/library/collections.html#collections.namedtuple) is having a smaller memory footprint for _mass_ results (long lists of tuples, such as results of DB queries). For individual items (if the function in question is not called often) dictionaries and classes are just fine as well. But namedtuples are a nice/nicer solution in this case as well. – Lutz Prechelt Feb 23 '16 at 17:07
  • 1
    Best answer I think. One thing that I didn't realize immediately - you don't need to declare the namedtuple in the outer scope; your function itself can define the container and return it. – wom Dec 15 '16 at 14:05
  • 9
    @wom: Don't do this. Python makes no effort to uniquify `namedtuple` definitions (each call creates a new one), creating the `namedtuple` class is relatively expensive in both CPU and memory, and all class definitions intrinsically involve cyclic references (so on CPython, you're waiting for a cyclic GC run for them to be released). It also makes it impossible to `pickle` the class (and therefore, impossible to use instances with `multiprocessing` in most cases). Each creation of the class on my 3.6.4 x64 consumes ~0.337 ms, and occupies just under 1 KB of memory, killing any instance savings. – ShadowRanger Apr 20 '18 at 19:20
  • 3
    I will note, Python 3.7 [improved the speed of creating new `namedtuple` classes](https://docs.python.org/3.7/whatsnew/3.7.html#api-and-feature-removals); [the CPU costs drop by roughly a factor of 4x](https://bugs.python.org/issue28638#msg298631), but they're still roughly 1000x higher than the cost to create an instance, and the memory cost for each class remains high (I was wrong in my last comment about "under 1 KB" for the class, `_source` by itself is typically 1.5 KB; `_source` is removed in 3.7, so it's likely closer to the original claim of just under 1 KB per class creation). – ShadowRanger Apr 20 '18 at 19:31
  • What a pity this is not in the standard library. One needs to `import collections`. This is why I keep using dictionaries. – Serge Stroobandt Sep 16 '18 at 17:38
  • 5
    @SergeStroobandt - This is part of the standard library, just not a builtin. You don't need to worry that it might not be installed on another system with Python >= 2.6. Or do you just object to the extra line of code? – Justin Oct 09 '18 at 19:14
  • Wouldn't types.SimpleNamespace be a better option as of now? – jaaq Jul 29 '19 at 11:06
  • @jaaq Why would that be better? – endolith Oct 26 '19 at 15:42
  • 1
    @endolith because you can add values after you create it, meaning you can add the results to the retval Namespace as soon as you get them and don't have to wait until you can put them in a named tuple all at once. Can reduce clutter in bigger functions by a lot sometimes. – jaaq Oct 27 '19 at 12:45
  • @jaaq: Problem is that `types.SimpleNamespace` is a glorified `dict`. Which means significantly higher memory cost per instance, increased cost to create, no ability to unpack like a `tuple`, etc. – ShadowRanger Nov 27 '19 at 00:16
250

For small projects I find it easiest to work with tuples. When that gets too hard to manage (and not before) I start grouping things into logical structures, however I think your suggested use of dictionaries and ReturnValue objects is wrong (or too simplistic).

Returning a dictionary with keys "y0", "y1", "y2", etc. doesn't offer any advantage over tuples. Returning a ReturnValue instance with properties .y0, .y1, .y2, etc. doesn't offer any advantage over tuples either. You need to start naming things if you want to get anywhere, and you can do that using tuples anyway:

def get_image_data(filename):
    [snip]
    return size, (format, version, compression), (width,height)

size, type, dimensions = get_image_data(x)

IMHO, the only good technique beyond tuples is to return real objects with proper methods and properties, like you get from re.match() or open(file).

Boris
  • 7,044
  • 6
  • 62
  • 63
too much php
  • 81,874
  • 33
  • 123
  • 133
  • 6
    Question - is there any difference between `size, type, dimensions = getImageData(x)` and `(size, type, dimensions) = getImageData(x)`? I.e., does wrapping left-hand-side of a tupled assignment make any difference? – Reb.Cabin Dec 28 '14 at 17:15
  • 12
    @Reb.Cabin There is no difference. Tuple is identified by comma and the use of parentheses is just to group things together. For example`(1)` is a int while `(1,)` or `1,` is a tuple. – phil May 14 '15 at 07:04
  • 23
    Re "returning a dictionary with keys y0, y1, y2 etc doesn't offer any advantage over tuples": dictionary has the advantage in that you can add fields to the returned dictionary without breaking existing code. – ostrokach Aug 28 '16 at 21:10
  • 2
    Re "returning a dictionary with keys y0, y1, y2 etc doesn't offer any advantage over tuples": it's also more readable and less error prone as you access the data based on its name rather than position. – Denis Dollfus Jan 16 '20 at 13:09
221

A lot of the answers suggest you need to return a collection of some sort, like a dictionary or a list. You could leave off the extra syntax and just write out the return values, comma-separated. Note: this technically returns a tuple.

def f():
    return True, False
x, y = f()
print(x)
print(y)

gives:

True
False
Joe
  • 10,698
  • 7
  • 47
  • 63
  • 25
    You are still returning a collection. It is a tuple. I prefer parenthesis to make it more explicit. Try this:``type(f())`` returns ````. – Igor May 17 '16 at 18:52
  • 22
    @Igor: There is no reason to make the `tuple` aspect explicit; it's not really important that you're returning a `tuple`, this is the idiom for returning multiple values period. Same reason you omit the parens with the swap idiom, `x, y = y, x`, multiple initialization `x, y = 0, 1`, etc.; sure, it makes `tuple`s under the hood, but there is no reason to make that explicit, since the `tuple`s aren't the point at all. The Python tutorial [introduces multiple assignment](https://docs.python.org/3/tutorial/introduction.html#first-steps-towards-programming) long before it even touches on `tuple`s. – ShadowRanger Apr 20 '18 at 19:39
  • @ShadowRanger any sequence of values separated by a comma in the right hand side of `=` is a tuple in Python with or without parenthesis around them. So there's actually no explicit or implicit here. a,b,c is as much a tuple as (a,b,c). There's also no making of tuple "under the hood" when you return such values, because it's just a plain simple tuple. The OP already mentioned tuples so there's actually no difference between what he mentioned and what this answer shows. None – Ken4scholars Jan 23 '19 at 19:25
  • @Ken4scholars: Yes, the language definition treats them as equivalent. That said, actual programmers tend to treat parentheses as indicating a sequence data structure, while without them, it's just "multiple things". I agree there is no difference in behavior, but the extra parens change the way most folks I know think about it. Agreed it's no different from the OP's example in behavior (with all the same limitations the OP didn't like). – ShadowRanger Jan 23 '19 at 22:12
  • 2
    This is the literally the first option suggested in the question – endolith Oct 26 '19 at 15:43
  • 1
    @endolith The two times the guy asks a question ("How do I return multiple values?" and "How do *you* return multiple values?") are answered by this answer. The text of the question has changed sometimes. And it's an opinion-based question. – Joe Feb 19 '20 at 14:22
79

I vote for the dictionary.

I find that if I make a function that returns anything more than 2-3 variables I'll fold them up in a dictionary. Otherwise I tend to forget the order and content of what I'm returning.

Also, introducing a 'special' structure makes your code more difficult to follow. (Someone else will have to search through the code to find out what it is)

If your concerned about type look up, use descriptive dictionary keys, for example, 'x-values list'.

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }
monkut
  • 36,357
  • 21
  • 109
  • 140
  • 5
    after many years of programming, I tend toward what ever the structure of the data and function is required. Function first, you can always refactor as is necessary. – monkut Jun 03 '14 at 02:59
  • How would we get the values within the dictionary without calling the function multiple times? For example, if I want to use y1 and y3 in a different function? – Matt Nov 02 '14 at 01:19
  • 4
    assign the results to a separate variable. `result = g(x); other_function(result)` – monkut Nov 04 '14 at 01:09
  • 1
    @monkut yes. This way also allows to pass result to several functions, which take different args from result, without having to specifically reference particular parts of the result every time. – Gnudiff Jan 07 '18 at 22:45
41

Another option would be using generators:

>>> def f(x):
        y0 = x + 1
        yield y0
        yield x * 3
        yield y0 ** 4


>>> a, b, c = f(5)
>>> a
6
>>> b
15
>>> c
1296

Although IMHO tuples are usually best, except in cases where the values being returned are candidates for encapsulation in a class.

rlms
  • 9,314
  • 8
  • 37
  • 58
  • 1
    This seems to be the cleanest solution, and has a clean syntax. Are there any downsides to this? If you don't use all the returns, are there 'unspent' yields waiting to hurt you? – Jiminion Dec 16 '15 at 14:08
  • 24
    This may be "clean", but it doesn't seem intuitive at all. How would someone who's never encountered this pattern before know that doing automatic tuple unpacking would trigger each `yield`? – coredumperror Jan 06 '16 at 21:38
  • 1
    @CoreDumpError, generators are just that… generators. There is no external difference between `def f(x): …; yield b; yield a; yield r` vs. `(g for g in [b, a, r])`, and both will readily convert to lists or tuples, and as such will support tuple unpacking. The tuple generator form follows a functional approach, while the function form is imperative and will allow flow control and variable assignment. – sleblanc Jan 28 '19 at 07:14
34

I prefer:

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

It seems everything else is just extra code to do the same thing.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
UnkwnTech
  • 79,308
  • 64
  • 178
  • 223
  • 24
    Tuples are easier to unpack: y0, y1, y2 = g() with a dict you have to do: result = g() y0, y1, y2 = result.get('y0'), result.get('y1'), result.get('y2') which is a little bit ugly. Each solution has its 'pluses' and its 'minuses'. – Oli Dec 10 '08 at 07:46
31

I prefer to use tuples whenever a tuple feels "natural"; coordinates are a typical example, where the separate objects can stand on their own, e.g. in one-axis only scaling calculations, and the order is important. Note: if I can sort or shuffle the items without an adverse effect to the meaning of the group, then I probably shouldn't use a tuple.

I use dictionaries as a return value only when the grouped objects aren't always the same. Think optional email headers.

For the rest of the cases, where the grouped objects have inherent meaning inside the group or a fully-fledged object with its own methods is needed, I use a class.

tzot
  • 81,264
  • 25
  • 129
  • 197
29
>>> def func():
...    return [1,2,3]
...
>>> a,b,c = func()
>>> a
1
>>> b
2
>>> c
3
WebQube
  • 6,772
  • 9
  • 40
  • 76
24

Generally, the "specialized structure" actually IS a sensible current state of an object, with its own methods.

class Some3SpaceThing(object):
  def __init__(self,x):
    self.g(x)
  def g(self,x):
    self.y0 = x + 1
    self.y1 = x * 3
    self.y2 = y0 ** y3

r = Some3SpaceThing( x )
r.y0
r.y1
r.y2

I like to find names for anonymous structures where possible. Meaningful names make things more clear.

tzot
  • 81,264
  • 25
  • 129
  • 197
S.Lott
  • 359,791
  • 75
  • 487
  • 757
20

Python's tuples, dicts, and objects offer the programmer a smooth tradeoff between formality and convenience for small data structures ("things"). For me, the choice of how to represent a thing is dictated mainly by how I'm going to use the structure. In C++, it's a common convention to use struct for data-only items and class for objects with methods, even though you can legally put methods on a struct; my habit is similar in Python, with dict and tuple in place of struct.

For coordinate sets, I'll use a tuple rather than a point class or a dict (and note that you can use a tuple as a dictionary key, so dicts make great sparse multidimensional arrays).

If I'm going to be iterating over a list of things, I prefer unpacking tuples on the iteration:

for score,id,name in scoreAllTheThings():
    if score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(score,id,name)

...as the object version is more cluttered to read:

for entry in scoreAllTheThings():
    if entry.score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry.score,entry.id,entry.name)

...let alone the dict.

for entry in scoreAllTheThings():
    if entry['score'] > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry['score'],entry['id'],entry['name'])

If the thing is widely used, and you find yourself doing similar non-trivial operations on it in multiple places in the code, then it's usually worthwhile to make it a class object with appropriate methods.

Finally, if I'm going to be exchanging data with non-Python system components, I'll most often keep them in a dict because that's best suited to JSON serialization.

Russell Borogove
  • 16,687
  • 3
  • 37
  • 45
20

+1 on S.Lott's suggestion of a named container class.

For Python 2.6 and up, a named tuple provides a useful way of easily creating these container classes, and the results are "lightweight and require no more memory than regular tuples".

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
John Fouhy
  • 37,154
  • 18
  • 59
  • 73
4

In languages like Python, I would usually use a dictionary as it involves less overhead than creating a new class.

However, if I find myself constantly returning the same set of variables, then that probably involves a new class that I'll factor out.

fluffels
  • 3,946
  • 7
  • 33
  • 51
4

I would use a dict to pass and return values from a function:

Use variable form as defined in form.

form = {
    'level': 0,
    'points': 0,
    'game': {
        'name': ''
    }
}


def test(form):
    form['game']['name'] = 'My game!'
    form['level'] = 2

    return form

>>> print(test(form))
{u'game': {u'name': u'My game!'}, u'points': 0, u'level': 2}

This is the most efficient way for me and for processing unit.

You have to pass just one pointer in and return just one pointer out.

You do not have to change functions' (thousands of them) arguments whenever you make a change in your code.

Elis Byberi
  • 1,360
  • 1
  • 10
  • 18
  • 1
    Dicts are mutable. If you pass a dict to a function and that function edits the dict, changes will be reflected outside the scope of that function. Having the function return the dict at the end might imply that the function has no side-effects, therefore the value should not be returned, making it clear that `test` will directly modify the value. Compare this with `dict.update`, which does not return a value. – sleblanc Jan 28 '19 at 07:01
  • @sleblanc "Having the function return the dict at the end might imply that the function has no side-effects". It does not imply that because ,as you said, dict is mutable. However, returning `form` does not hurt readability nor performance. In cases where you may need to reformat `form`, returning it [form] does make sure that the last `form` is returned because you will not keep track of form changes anywhere. – Elis Byberi Jan 28 '19 at 14:03
4

"Best" is a partially subjective decision. Use tuples for small return sets in the general case where an immutable is acceptable. A tuple is always preferable to a list when mutability is not a requirement.

For more complex return values, or for the case where formality is valuable (i.e. high value code) a named tuple is better. For the most complex case an object is usually best. However, it's really the situation that matters. If it makes sense to return an object because that is what you naturally have at the end of the function (e.g. Factory pattern) then return the object.

As the wise man said:

Premature optimization is the root of all evil (or at least most of it) in programming.

joel3000
  • 1,039
  • 9
  • 17