1

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)
3
  • 4
    If there's a problem, raise an exception. Commented Jun 5, 2014 at 4:13
  • I don't want to raise an exception. I just need to feed two None to var_1 and var_2 so they are happy.... but with a nicer syntax. By some reason I dislike return None, None syntax. But if there is no way around it I will take it as is. Commented Jun 5, 2014 at 4:14
  • I think it depends on what you later do with var_1 and var_2. All of the solutions posted here are good, but which one is right probably depends on the greater context of your program. Commented Jun 5, 2014 at 4:33

4 Answers 4

3

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"
Sign up to request clarification or add additional context in comments.

3 Comments

This is nice as it fits with Python's "ask for forgiveness, not permission" idiom, however it does mask TypeErrors that are occurring within the function (rather than in the expansion).
And the way to solve that is to raise an exception within the function. Or, if it makes sense that both variables should return undefined values, return None,None. Both of these solutions have been specifically disallowed by the questioner.
I agree that returning None, None seems to make sense from the information supplied.
2

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.

Comments

2

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)

1 Comment

Interesting! A nice way to put it
1

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

2 Comments

That's pretty cool! I've never realized a single variable can be used to catch a returned value: it doesn't matter a single or multiple are returned. If None is returned result is None. If two values are returned result is tuple. I just would never use var_1 and var_2 since if result: then do this..
Yes, return a, b is equivalent to return (a, b) - it returns a tuple of the values. The feature that allows you to view it as two separate values is called "unpacking" (docs.python.org/2/tutorial/…) and works with any iterable - eg a, b, c = xrange(3), or a, b, c = '123'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.