In my code I need to detect if a variable is a function or not and preform some actions on it.
Everything went well until I now created a partial function using functools
and suddenly some of my tests fail:
import types
import functools
def f(s):
print(s)
l = lambda s: print(s)
pf = functools.partial(f, 'Hello World')
pl = functools.partial(l, 'Hello World')
test_f = isinstance(f, types.FunctionType) # True
test_l = isinstance(l, types.FunctionType) # True
test_pf = isinstance(pf, types.FunctionType) # False
test_pl = isinstance(pl, types.FunctionType) # False
Why is there a difference between those? Both varieties are callable... Even more importantly, how can I detect if some variable is a function or not even when it's a partial function if I can't use types.FunctionType
?
functools.partial
is a class with a __call__
method, it says in the documents:
Return a new
partial
object which when called will behave like func
(bold emphasis added by me)
We can confirm this in our Python REPL:
>>> from functools import partial
>>> add_one = partial(sum, 1)
>>> type(add_one)
<class 'functools.partial'>
A Python equivalent would be something like this:
class Partial:
def __init__(self, func, *args, **kwargs):
self.func = func
self.args = args
self.kwargs = kwargs
def __call__(self, *args, **kwargs):
return self.func(*self.args, *args, **self.kwargs, **kwargs)
So it creates a simple wrapper object around the function, and an object like this simply isn't a function. types.FunctionType
only works on actual functions.
What you're looking for is a way to check if an object is callable, for that you can use the built-in callable
function:
>>> callable(sum)
True
>>> callable(3)
False
>>> callable(functools.partial(sum, 1))
True