Toothpick Anemone
Toothpick Anemone

Reputation: 4644

How do we check if a function returns mutiple values in Python?

This question was already asked, but I wish to ask something subtly different.

How do we determine if a python function returns multiple values, without calling the function? Is there some way to find out at something more like compile-time instead of at run-time? (I realize that python is an interpreted language)

The following is out of the question:

r = demo_function(data) # takes more than 5 minutes to run
if (not len(r) == 2) or (not isinstance(r, tuple)):
    raise ValueError("I was supposed to return EXACTLY two things")

So is:

try:
    i, j = demo_function(data)
    # I throw TypeError: 'int' object is not iterable
except ValueError:
    raise ValueError("Hey! I was expecting two values.")
except TypeError:
    s1 = "Hey! I was expecting two values."
    s2 = "Also, TypeError was thrown, not ValueError"
    raise ValueError(s1 + s2)

The following sort of works, but is extremely inelegant:

r = demo_function(extremely_pruned_down_toy_data) # runs fast
if len(r) != 2:
    raise ValueError("There are supposed to be two outputs")
# Now we run it for real
r = demo_function(data) # takes more than 5 minutes to run

There are tools already in python which do similar things. For example, we can find out if a class object has a certain attribute:

prop_str = 'property'
if not hasattr(obj, prop_str):
    raise ValueError("There is no attribute named" + prop_str + " NOOOOoooo! ")

Also, we can find out how many INPUTS a function has:

from inspect import signature

sig = signature(demo_function)
p = sig.parameters
if len(p)) != 2:
raise ValueError("The function is supposed to have 2 inputs, but it has" + str(p))

I basically want the following:

p = nargout(demo_function)
if p != 2:
    raise ValueError("The function is supposed to have 2 outputs, but it has" + str(p))

Asking what a function returns is one of the most basic things questions one can ask about a function. It feels really weird that I'm having trouble finding out.

EDIT:

juanpa.arrivillaga wrote,

[...] fundamentally, this points to a deeper, underlying design flaw: why do you have functions that can return different length containers when you are expecting a specific length?

Well, let me explain. I have something like this:

def process_data(data_processor, data):
    x, y =  data_processor(data)
    return x, y

A precondition of the process_data function is that the input data_processor MUST return two items. As such, I want to write some error checking code to enforce the precondition.

def process_data(data_processor, data):
    # make sure data_processor returns exactly two things!
    verify_data_processor(data_processor)
    x, y =  data_processor(data)
    return x, y

However, it looks like that's not easily doable.

Upvotes: 4

Views: 101

Answers (1)

juanpa.arrivillaga
juanpa.arrivillaga

Reputation: 95873

A function really only has a single return value. It can return a container, such as a tuple, of whatever length. But there is no inherent way for a Python function to know the length of such a value, Python is much too dynamic. Indeed, in general, the interpreter does not know the nature of the return value of a function. But even if we stick to just considering functions that return containers, consider the following function:

def howmany(n):
    return n*('foo',)

Well, what should nargout(howmany) return?

And python does not special case something like return x, y, nor should it, because then what should be the behavior when the length of the returned container is indeterminate, such as return n*(1,)? No, it is up to the caller to deal with the case of a function returning a container, in one of the ways you've already illustrated.

And fundamentally, this points to a deeper, underlying design flaw: why do you have functions that can return different length containers when you are expecting a specific length?

Upvotes: 5

Related Questions