The canonical way to return multiple values in languages that support it is often tupling.
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.
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']
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.
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)
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.
After the lengthy preamble, comes the inevitable question. Which method (do you think) is best?
We can return more than one values from a function by using the method called “call by address”, or “call by reference”. In the invoker function, we will use two variables to store the results, and the function will take pointer type data.
Python functions can return multiple values. These values can be stored in variables directly. A function is not restricted to return a variable, it can return zero, one, two or more values.
No, you can not return multiple values like this in C. A function can have at most one single return value.
You can return only one value in Java. If needed you can return multiple values using array or an object.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With