SoFunction
Updated on 2024-11-15

Three ways to determine whether a python object is callable and their differences in detail

Looking up the information, basically there are three ways to determine whether a python object is a callable function or not

Using the built-in callable function

callable(func)

Used to check whether the object can be called, return True may also fail to call, but return False must not be called.

Official Documentation:/3/library/?highlight=callable#callable

Determine if an object type is a FunctionType.

type(func) is FunctionType
# Or
isinstance(func, FunctionType)

Determine whether an object implements the __call__ method.

hasattr(func, '__call__')

Write a small demo to test the difference between these three authentication methods

from types import FunctionType
__author__ = 'blackmatrix'


class ClassA:

 @staticmethod
 def func_a():
  pass

 @classmethod
 def func_b(cls, arg):
  pass

 def func_c(self, arg):
  pass


def func_d():
 pass

if __name__ == '__main__':

 class_a = ClassA()

 print('Static methods, instance call validation')
 print("callable(class_a.func_a) result: {result}".format(result=callable(class_a.func_a)))
 print("type(class_a.func_a) is FunctionType result: {result}".format(result=type(class_a.func_a) is FunctionType))
 print("hasattr(class_a.func_a, '__call__') result: {result}".format(result=hasattr(class_a.func_a, '__call__')))

 print('Static methods, class call validation')
 print("callable(ClassA.func_a) result: {result}".format(result=callable(ClassA.func_a)))
 print("type(ClassA.func_a) is FunctionType result: {result}".format(result=type(ClassA.func_a) is FunctionType))
 print("hasattr(ClassA.func_a, '__call__') result: {result}".format(result=hasattr(ClassA.func_a, '__call__')))

 print('Class method validation')
 print("callable(ClassA.func_b) result: {result}".format(result=callable(ClassA.func_b)))
 print("type(ClassA.func_b) is FunctionType result: {result}".format(result=type(ClassA.func_b) is FunctionType))
 print("hasattr(ClassA.func_b, '__call__') result: {result}".format(result=hasattr(ClassA.func_b, '__call__')))

 print('Instance method validation')
 print("callable(class_a.func_c) result: {result}".format(result=callable(class_a.func_c)))
 print("type(class_a.func_c) is FunctionType result: {result}".format(result=type(class_a.func_c) is FunctionType))
 print("hasattr(class_a.func_c, '__call__') result: {result}".format(result=hasattr(class_a.func_c, '__call__')))

 print('Function Validation')
 print("callable(func_d) result: {result}".format(result=callable(func_d)))
 print("type(func_d) is FunctionType result: {result}".format(result=type(func_d) is FunctionType))
 print("hasattr(func_d, '__call__') result: {result}".format(result=hasattr(func_d, '__call__')))

By running the results, it was found that the validation results of the three methods were not the same.

Mainly the type(func) is FunctionType method, which returns False when validating class methods against instance methods.

From the debugging result, the type of instance method, and class method are <class 'method'>, not FunctionType, so it will return False.

static method,Instance call validation
callable(class_a.func_a) result: True
type(class_a.func_a) is FunctionType result: True
hasattr(class_a.func_a, '__call__') result: True
static method,Class call validation
callable(ClassA.func_a) result: True
type(ClassA.func_a) is FunctionType result: True
hasattr(ClassA.func_a, '__call__') result: True
Class Method Validation
callable(ClassA.func_b) result: True
type(ClassA.func_b) is FunctionType result: False
hasattr(ClassA.func_b, '__call__') result: True
Instance Method Validation
callable(class_a.func_c) result: True
type(class_a.func_c) is FunctionType result: False
hasattr(class_a.func_c, '__call__') result: True
function verification
callable(func_d) result: True
type(func_d) is FunctionType result: True
hasattr(func_d, '__call__') result: True

Because Python is divided into function (function) and method (method), function is a callable object in Python (user-defined callable objects, and functions created by lambda expressions, are functions, whose type is FunctionType), and method is a special kind of class function.

Definition of method in the official documentation:

Methods are always bound to an instance of a user-defined class

Class methods are bound to classes and instance methods are bound to instances, so both are of type method.

Static methods, on the other hand, are not bound to classes or instances, and do not meet the above definition, so their type should be function.

One of the other things to note is that if a class implements the __call__ method, then its instance also becomes a callable object of the type of the class that created it, rather than a function or method.

class TheClass:

 def __call__(self, *args, **kwargs):
  return self

if __name__ == '__main__':
the_class = TheClass()
# True
print('class_instance callable {callable} '.format(callable=callable(the_class)))

So to determine whether a Python object is callable by type, you need to determine both whether it is a function (FunctionType) or a method (MethodType), or whether the class implements the __call__ method.

If you are simply determining whether a python object is callable or not, it would be more prudent to use the callable() method.

The above three ways of determining whether a python object is callable and their differences in detail is all that I have shared with you, and I hope it will give you a reference, and I hope you will support me more.