How to find out if a function has been declared by `lambda` or `def`?

function, function-declaration, lambda, python, types

Solution

AFAIK, you cannot reliably in Python 3.

Python 2 used to define a bunch of function types. For that reason, methods, lambdas and plain functions have each their own type.

Python 3 has only one type which is `function`. There are indeed different side effects where declaring a regular function with `def` and a `lambda`: `def` sets the name to the name (and qualified name) of the function and can set a docstring, while `lambda` sets the name (and qualified name) to be `<lambda>`, and sets the docstring to None. But as this can be changed...

If the functions are loaded from a regular Python source (and not typed in an interactive environment), the `inspect` module allows to access the original Python code:

import inspect

def f(x):
    return x**2

g = lambda x: x**2

def is_lambda_func(f):
    """Tests whether f was declared as a lambda.

Returns: True for a lambda, False for a function or method declared with def
Raises:
    TypeError if f in not a function
    OSError('could not get source code') if f was not declared in a Python module
                                         but (for example) in an interactive session
"""
    if not inspect.isfunction(f):
        raise TypeError('not a function')
    src = inspect.getsource(f)
    return not src.startswith('def') and not src.startswith('@') # provision for decorated funcs

g.__name__ = 'g'
g.__qualname__ = 'g'

print(f, is_lambda_func(f))
print(g, is_lambda_func(g))

This will print:

<function f at 0x00000253957B7840> False
<function g at 0x00000253957B78C8> True

By the way, if the problem was serialization of function, a function declared as a lambda can successfully be pickled, provided you give it a unique qualified name:

>>> g = lambda x: 3*x
>>> g.__qualname__ = "g"
>>> pickle.dumps(g)
b'\x80\x03c__main__\ng\nq\x00.'

Problem

If I declare two functions `a` and `b`: ``` def a(x): return x**2 b = lambda x: x**2 ``` I can not use `type` to differentiate them, since they're both of the same type. ``` assert type(a) == type(b) ``` Also, `types.LambdaType` doesn't help: ``` >>> import types >>> isinstance(a, types.LambdaType) True >>> isinstance(b, types.LambdaType) True ``` One could use `__name__` like: ``` def is_lambda_function(function): return function.__name__ == "<lambda>" >>> is_lambda_function(a) False >>> is_lambda_function(b) True ``` However, since `__name__` could have been modified, `is_lambda_function` is not guaranteed to return the correct result: ``` >>> a.__name__ = '<lambda>' >>> is_lambda_function(a) True ``` Is there a way which produces a more reliable result than the `__name__` attribute?

Original source

Related problems