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?
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.'
You can check __code__.co_name
. It contains what the name was at the time the function/lambda was compiled:
def a(x):
return x**2
b = lambda x: x**2
def is_lambda_function(f):
return f.__code__.co_name == "<lambda>"
>>> is_lambda_function(a)
False
>>> is_lambda_function(b)
True
And, contrary to __name__
, __code__.co_name
is read-only...
>>> a.__name__ = "<lambda>"
>>> b.__name__ = "b"
>>> a.__code__.co_name = "<lambda>"
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: readonly attribute
>>> b.__code__.co_name = "b"
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: readonly attribute
... so the results will stay the same:
>>> is_lambda_function(a)
False
>>> is_lambda_function(b)
True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With