An Exact Function Checker
callable is a very good solution. However, I wanted to treat this the opposite way of John Feminella. Instead of treating it like this saying:
The proper way to check properties of duck-typed objects is to ask them if they quack, not to see if they fit in a duck-sized container. The "compare it directly" approach will give the wrong answer for many functions, like builtins.
We'll treat it like this:
The proper way to check if something is a duck is not to see if it can quack, but rather to see if it truly is a duck through several filters, instead of just checking if it seems like a duck from the surface.
How Would We Implement It
The 'types' module has plenty of classes to detect functions, the most useful being types.FunctionType, but there are also plenty of others, like a method type, a built in type, and a lambda type. We also will consider a 'functools.partial' object as being a function.
The simple way we check if it is a function is by using an isinstance condition on all of these types. Previously, I wanted to make a base class which inherits from all of the above, but I am unable to do that, as Python does not allow us to inherit from some of the above classes.
Here's a table of what classes can classify what functions:
Above function table by kinght-金
The Code Which Does It
Now, this is the code which does all of the work we described from above.
from types import BuiltinFunctionType, BuiltinMethodType, FunctionType, MethodType, LambdaType
from functools import partial
def is_function(obj):
return isinstance(obj, (BuiltinFunctionType, BuiltinMethodType, FunctionType, MethodType, LambdaType, partial))
#-------------------------------------------------
def my_func():
pass
def add_both(x, y):
return x + y
class a:
def b(self):
pass
check = [
is_function(lambda x: x + x),
is_function(my_func),
is_function(a.b),
is_function(partial),
is_function(partial(add_both, 2))
]
print(check)
>>> [True, True, True, False, True]
The one false was is_function(partial), because that's a class, not a function, and this is exactly functions, not classes. Here is a preview for you to try out the code from.
Conclusion
callable(obj) is the preferred method to check if an object is a function if you want to go by duck-typing over absolutes.
Our custom is_function(obj), maybe with some edits is the preferred method to check if an object is a function if you don't any count callable class instance as a function, but only functions defined built-in, or with lambda, def, or partial.
And I think that wraps it all up. Have a good day!