alphanumeric
alphanumeric

Reputation: 19329

How to return from function nicely when multiple return values expected

The myFunct is expected to return two values. Both returned values are captured to var_1, var_2.

As an error check I am using a lot of if/else: return statement inside of scope of the function called (myFunct in this case). Typing simple if arg<10: return returns a single None which raises TypeError: 'NoneType' object is not iterable since there are two variables: var_1, var_2 = myFunct(5) expecting two returned values but only a single value None is returned.

In order to avoid an error like this I would have to use a following syntax:

if arg<10: return None, None

which I find pretty ugly.

I wonder if there is a nicer way to do it...

def myFunct(arg):
    if arg<10:
        return
    return 100, 200

var_1, var_2 = myFunct(5)

Upvotes: 1

Views: 1660

Answers (4)

AMADANON Inc.
AMADANON Inc.

Reputation: 5919

If something is broken, the correct solution is to raise an exception. However, if you definitely don't want to do this, you could always:

try:
    var_1, var_2 = myFunct(5)
except TypeError:
    var_1, var_2 = (None,None)

Edit:

Perhaps you need to think about what you are going to do with your var_1 and var_2 if they are indeed None. If you are going to continue a calculation for which None is a valid input, then probably return None,None is the correct expression. If, however, this is an exception, and you are going to note that the result is None, and do something completely different (which does not have two values), then you can always do this:

result = myFunct(5)
if result:
    var_1,var_2=result
    do_more_stuff_here_with(var_1 and var_2) # logical and :)
else:
    print "myFunct(5) failed - check (and if necessary adjust) the phase of the moon"

Upvotes: 3

Chris Martin
Chris Martin

Reputation: 30736

How about a lovely decorator?

import decorator

def default_return_value(value):
    @decorator.decorator
    def decorate(f, *args, **kwargs):
        x = f(*args, **kwargs)
        return value if x is None else x
    return decorate

def returns_tuple(size):
    return default_return_value(tuple([None] * size))

@returns_tuple(size=2)
def myFunct(arg):
    if arg >= 10:
        return 100, 200

>>> myFunct(15)
(100, 200)

>>> myFunct(5)
(None, None)

Upvotes: 2

aruisdante
aruisdante

Reputation: 9075

While this is debatable, it's usually considered good practice to have a single point of exit. In other words, only one return statement. You can accomplish this as follows,

def myFunc(arg):
    result1, result2 = None, None
    if not arg < 10:
        result1, result2 = 100,200
    return result1, result2

Now obviously, your toy example is so simple there are even more pythonic ways you can simplify this specific example, such as:

def myFunc(arg):
    return (None, None) if arg < 10 else (100,200)

But the single point of exit is a good practice to get into for my complex functions.

And as others have pointed out, raising exceptions is the most pythonic way to signal that a function reached an error condition. None as a return should generally only be used to signal essentially the equivalent of an empty list, I.E. where getting nothing back is an expected possible outcome of the function.

Upvotes: 2

Peter Gibson
Peter Gibson

Reputation: 19534

Store the result in a single variable then expand it as needed

result = myFunct(5)
var_1, var_2 = (None, None) if result is None else result

Upvotes: 1

Related Questions