tags:

views:

1800

answers:

9

In python, you can have a function return multiple values. Here's a contrived example:

def divide(x, y):
    quotient = x/y
    remainder = x % y
    return quotient, remainder  

(q, r) = divide(22, 7)

This seems very useful, but it looks like it can also be abused ("Well..function X already computes what we need as an intermediate value. Let's have X return that value also").

When should you draw the line and define a different method?

+21  A: 

Firstly, note that Python allows for the following (no need for the parenthesis):

q, r = divide(22, 7)

Regarding your question, there's no hard and fast rule either way. For simple (and usually contrived) examples, it may seem that it's always possible for a given function to have a single purpose, resulting in a single value. However, when using Python for real-world applications, you quickly run into many cases where returning multiple values is necessary, and results in cleaner code.

So, I'd say do whatever makes sense, and don't try to conform to an artificial convention. Python supports multiple return values, so use it when appropriate.

Jason Etheridge
I'd be interested in seeing such a case, could you show one?
Vinko Vrsalovic
comma creates tuple, therefore expression: `q, r` *is* a tuple.
J.F. Sebastian
Vinko, an example is tempfile.mkstemp() from the standard library, which returns a tuple containing a file handle and an absolute path.JFS, yes, you're right.
Jason Etheridge
But that IS a single purpose... You can have single purpose and multiple return values
Vinko Vrsalovic
If other languages could have multiple return types, I wouldn't be stuck with references and 'out' parameters.
orip
Returning multiple values is one of the greatest feature in python!
Martin Beckett
+29  A: 

Absolutely (for the example you provided).

Tuples are first class citizens in Python

There is a builtin function divmod() that does exactly that.

q, r = divmod(x, y) # ((x - x%y)/y, x%y) Invariant: div*y + mod == x

There are other examples: zip, enumerate, dict.items.

for i, e in enumerate([1, 3, 3]):
    print "index=%d, element=%s" % (i, e)

# reverse keys and values in a dictionary
d = dict((v, k) for k, v in adict.items()) # or 
d = dict(zip(adict.values(), adict.keys()))

BTW, parentheses are not necessary most of the time. Citation from Python Library Refrence:

Tuples are constructed by the comma operator (not within square brackets), with or without enclosing parentheses, but an empty tuple must have the enclosing parentheses, such as a, b, c or (). A single item tuple must have a trailing comma, such as (d,).

Functions should serve single purpose

Therefore they should return a single object. In your case this object is a tuple. Consider tuple as an ad-hoc compound data structure. There are languages where almost every single function returns multiple values (list in Lisp).

Sometimes it is sufficient to return (x, y) instead of Point(x, y).

Named tuples

With introduction of named tuples in Python 2.6 It is preferable in many cases to return named tuples instead of plain tuples.

>>> import collections
>>> Point = collections.namedtuple('Point', 'x y')
>>> x, y = Point(0, 1)
>>> p = Point(x, y)
>>> x, y, p
(0, 1, Point(x=0, y=1))
>>> p.x, p.y, p[0], p[1]
(0, 1, 0, 1)
>>> for i in p:
...   print(i)
...
0
1
J.F. Sebastian
The ability to use tuples like that is so handy. I really miss having that ability in Java some times.
MBCook
Thanks a lot for mentioning Named tuples. I've been looking for something like this.
vobject
+9  A: 

The example you give is actually a python builtin function, called divmod. So someone, at some point in time, thought that it was pythonic enough to include in the core functionality.

To me, if it makes the code cleaner, it is pythonic. Compare these two code blocks:

seconds = 1234
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)

seconds = 1234
minutes = seconds / 60
seconds = seconds % 60
hours = minutes / 60
minutes = minutes % 60
Nathan Jones
A: 

It's fine to return multiple values using a tuple for simple functions such as divmod. If it makes the code readable, it's Pythonic.

If the return value starts to become confusing, check whether the function is doing too much and split it if it is. If a big tuple is being used like an object, make it an object. Also, consider using named tuples, which will be part of the standard library in Python 2.6.

Will Harris
+1  A: 

It's definitely pythonic. The fact that you can return multiple values from a function the boilerplate you would have in a language like C where you need to define a struct for every combination of types you return somewhere.

However, if you reach the point where you are returning something crazy like 10 values from a single function, you should seriously consider bundling them in a class because at that point it gets unwieldy.

indentation
+1  A: 

Returning a tuple is cool. Also note the new namedtuple which was added in python 2.6 which may make this more palatable for you: http://docs.python.org/dev/library/collections.html#collections.namedtuple

pixelbeat
+3  A: 
zweiterlinde
"a method that optionally handles an event and also returns success or failure" - That's what exceptions are for.
Nathan
+1  A: 

I'm fairly new to Python, but the tuple technique seems very pythonic to me. However, I've had another idea that may enhance readability. Using a dictionary allows access to the different values by name rather than position. For example:

def divide(x, y):
    return {'quotient': x/y, 'remainder':x%y }

answer = divide(22, 7)
print answer['quotient']
print answer['remainder']
Fred Larson
A: 

OT: RSRE's Algol68 has the curious "/:=" operator. eg.

INT quotient:=355, remainder;
remainder := (quotient /:= 113);

Giving a quotient of 3, and a remainder of 16.

Note: typically the value of "(x/:=y)" is discarded as quotient "x" is assigned by reference, but in RSRE's case the returned value is the remainder.

c.f. Integer Arithmetic - Algol68

NevilleDNZ