4

E.g.

def f1():
    return 1

def f2():
    return None

def f3():
    print("Hello")

Functions f1() and f2() returns something but f3() not.

a = f2()
b = f3()

And here a equals b so I can't just compare the result of functions to check if one has return or not.

Misha
  • 107
  • 1
  • 2
  • 9
  • 1
    `f3()` returns `None` because if you don't specify a return in Python it defaults the return to None. I assume you are asking if you can check if a user has actually specify a return or not ? – MooingRawr Jan 12 '18 at 19:27
  • 2
    Can you give an example of where it would be useful to distinguish between "explicitly returned None" and "implicitly returned None"? – Kevin Jan 12 '18 at 19:28

2 Answers2

10

I like st0le's idea of inspecting the source, but you can take it a step further and parse the source into a source tree, which eliminates the possibility of false positives.

import ast
import inspect

def contains_explicit_return(f):
    return any(isinstance(node, ast.Return) for node in ast.walk(ast.parse(inspect.getsource(f))))

def f1():
    return 1

def f2():
    return None

def f3():
    print("return")

for f in (f1, f2, f3):
    print(f, contains_explicit_return(f))

Result:

<function f1 at 0x01D151E0> True
<function f2 at 0x01D15AE0> True
<function f3 at 0x0386E108> False

Of course, this only works for functions that have source code written in Python, and not all functions do. For instance, contains_explicit_return(math.sqrt) will give you a TypeError.

Furthermore, this won't tell you anything about whether any particular execution of a function hit a return statement or not. Consider the functions:

def f():
    if random.choice((True, False)):
        return 1

def g():
    if False:
        return 1

contains_explicit_return will give True on both of these, despite f not encountering a return in half of its executions, and g not encountering a return ever.

Kevin
  • 72,202
  • 12
  • 116
  • 152
8

A function by definition always returns something. Even if you don't specify it, there is an implicit return None at the end of a python function.

You can check for a "return" with the inspect module.

EDIT: I just realized. This is horribly wrong because, it'll return True if there's a string literal in the function that has "return" in it. I suppose a robust a regex will help here.

from inspect import getsourcelines


def f(n):
    return 2 * n


def g(n):
    print(n)


def does_function_have_return(func):
    lines, _  = getsourcelines(func)
    return any("return" in line for line in lines) # might give false positives, use regex for better checks


print(does_function_have_return(f))
print(does_function_have_return(g))
st0le
  • 33,007
  • 8
  • 86
  • 89