简体   繁体   中英

How can I find out the number of outputs returned by a python function?

Imagine there are two Python functions:

def f1(x):
    return x

def f2(x):
    return x,x**2

I would like to find out how many outputs are returned by f1 and how many outputs are returned by f2 .

I would like to avoid the following solution:

result = f1(1)
no_outputs = len(result) if type(result) == tuple else 1

Since this solution fails when a function returns a tuple.

I started playing around with the python ast (abstract syntax tree) library, and was wondering if there was any way to parse the syntax tree for a function to figure out the number of outputs returned?

Something along the lines of:

import inspect
import ast

src = inspect.getsourcelines(f1)[0]

string = ''.join(src)
ast_   = ast.parse(string)

I explored ast_ but am not able to find what the returns are.

Technically a function returns ONE value. That one value might be a tuple, a dictionary, or any arbitrarily complex object (including collection objects).

The appearance of multiple return values is merely the result of some syntactic sugar around automatic unpacking and the fact that the tuple operator in Python is actually the , (the comma; the parentheses are not necessary in a return statement and only required in cases where the , (comma) would be ambiguous).

Because Python is dynamically typed a function can return different types of values (objects) depending on its arguments or on the program's global state when it's called. It can return different types of objects for different calls during the same program (interpreter/VM) session.

You should consider the return type of a function to be a matter of documentation ... any well written Python function will document its return type (preferably in the doc string).

It is fairly common for methods of classes that are wrapped around some data structure to return self ... which allows for a "chained usage" pattern: Foo.fiddle().faddle().spritz().output() ... where we perform a whole series of operations on the object all in a single, concise expression.

I agree with the comments that this is a somewhat curious question... However, to answer your question following the approach you propose, let's start with the following simplifying assumptions:

  1. There is only one return statement, which occurs at the very end of each function

  2. Commas can be used to determine the "number of outputs", ie (x, 2) and x, 2 are both considered to be two "outputs"

  3. Following from point 2, return statements are comprised of a series of variables (possibly as lists or tuples), and never more complicated expressions like generators or list comprehensions

We assume the above because otherwise you would almost certainly need to properly parse the subset of valid Python code, eg by building an AST. Given the above, you take the last string from the list returned by inspect.getsourcelines() and match a regular expression:

In [47]: def f2(x):
   ....:     return x, x**2

In [48]: ret2 = inspect.getsourcelines(f2)

In [49]: ret2
Out[49]: ([u'def f2(x):\n', u'    return x, x**2\n'], 1)

In [55]: ret_pattern = r'return\s*(.*)\n*$'

In [56]: out2 = re.findall(ret_pattern, ret2[0][-1])

In [57]: out2
Out[57]: [u'x, x**2']

In [58]: len(out2[0].split(','))
Out[58]: 2

Testing with returning a tuple of variables:

In [59]: def f3(x):
   ....:     return (x, x**2, x**3)
   ....:

In [62]: out3 = re.findall(ret_pattern, inspect.getsourcelines(f3)[0][-1])

In [63]: len(out3[0].split(','))
Out[63]: 3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM