Reputation: 1200
Suppose the following:
def MyFunc(a):
if a < 0:
return None
return (a+1, a+2, a+3)
v1, v2, v3 = MyFunc()
# Bad ofcourse, if the result was None
What is the best way to define a function that returns a tuple and yet can be nicely called. Currently, I could do this:
r = MyFunc()
if r:
v1, v2, v3 = r
else:
# bad!!
pass
What I don't like about this is that I have to use a single variable and then unpack it.
Another solution is I could have the function return a tuple full of Nones so that the caller can nicely unpack....
Anyone can suggest a better design?
Upvotes: 14
Views: 10463
Reputation: 11
This is similar to the previous answer. You could return either an object instance or None
def MyFunc(a):
class MyFuncClass(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
if a < 0:
return None
return MyFuncClass(one=a+1, two=a+2, three=a+3)
o = MyFunc(1)
if o is not None:
print o.one, o.two, o.three
Upvotes: 1
Reputation: 14961
If you want the v1, v2, v3
objects to exist and be set to a default value in the case of an error, return the default values yourself. This will make the calling code simpler by not relying on the caller to set them manually:
def MyFunc(a):
if a < 0:
# can't use a negative value; just return some defaults
return (None, None, None)
return (a+1, a+2, a+3)
On the other hand, if a default return is not appropriate and a negative argument is considered a serious error, raise an exception:
def MyFunc(a):
if a < 0:
# sorry, negative values are unacceptable
raise ValueError('cannot accept a negative value')
return (a+1, a+2, a+3)
On the third hard, returning None
may be preferable sometimes when returning a single object, as is the case with the search()
and match()
functions of the re
module. It somehow stands between the first two cases, because matching failure is an expected outcome, while a default return object wouldn't be very useful anyway.
Upvotes: 2
Reputation: 70819
How about raise an ArgumentError
? Then you could try
calling it, and deal with the exception if the argument is wrong.
So, something like:
try:
v1, v2, v3 = MyFunc()
except ArgumentError:
#deal with it
Also, see katrielalex's answer for using a subclass of ArgumentError.
Upvotes: 12
Reputation: 391846
Another solution is I could have the function return a tuple full of Nones so that the caller can nicely unpack....
What's wrong with that? Consistency is a good thing.
Upvotes: 4
Reputation: 123632
recursive
has a truly elegant and Pythonic solution. BUT: why do you want to return None
? Python has a way of handling errors, and that is by raising an exception:
class AIsTooSmallError( ArgumentError ): pass
and then
raise AIsTooSmallError( "a must be positive." )
The reason this is better is that returning a value indicates that you have completed processing and are passing back your answer. This is fine if you have done some processing, but it's silly if you are immediately returning None
.
Upvotes: 8
Reputation: 86084
This should work nicely:
v1, v2, v3 = MyFunc() or (None, None, None)
When MyFunc()
returns a tuple, it will be unpacked, otherwise it will be substituted for a 3-tuple of None
.
Upvotes: 10