文章目录
问题描述
Python判断一个对象是否为函数
解决方案
callable(x)
hasattr(x, '__call__')
inspect.isfunction(x)
inspect.ismethod(x)
inspect.isgeneratorfunction(x)
inspect.iscoroutinefunction(x)
inspect.isasyncgenfunction(x)
isinstance(x, typing.Callable)
isinstance(x, types.BuiltinFunctionType)
isinstance(x, types.BuiltinMethodType)
isinstance(x, types.FunctionType)
isinstance(x, types.MethodType)
isinstance(x, types.LambdaType)
isinstance(x, functools.partial)
import types
import inspect
import functools
import typing
def judge(x):
name = x.__name__ if hasattr(x, '__name__') else 'functools.partial'
print(name)
print('\ttype({})={}'.format(name, type(x)))
print('\tcallable({})={}'.format(name, callable(x)))
print('\thasattr({}, \'__call__\')={}'.format(name, hasattr(x, '__call__')))
print()
print('\tinspect.isfunction({})={}'.format(name, inspect.isfunction(x)))
print('\tinspect.ismethod({})={}'.format(name, inspect.ismethod(x)))
print('\tinspect.isgeneratorfunction({})={}'.format(name, inspect.isgeneratorfunction(x)))
print('\tinspect.iscoroutinefunction({})={}'.format(name, inspect.iscoroutinefunction(x)))
print('\tinspect.isasyncgenfunction({})={}'.format(name, inspect.isasyncgenfunction(x)))
print()
print('\tisinstance({}, typing.Callable)={}'.format(name, isinstance(x, typing.Callable)))
print('\tisinstance({}, types.BuiltinFunctionType)={}'.format(name, isinstance(x, types.BuiltinFunctionType)))
print('\tisinstance({}, types.BuiltinMethodType)={}'.format(name, isinstance(x, types.BuiltinMethodType)))
print('\tisinstance({}, types.FunctionType)={}'.format(name, isinstance(x, types.FunctionType)))
print('\tisinstance({}, types.MethodType)={}'.format(name, isinstance(x, types.MethodType)))
print('\tisinstance({}, types.LambdaType)={}'.format(name, isinstance(x, types.LambdaType)))
print('\tisinstance({}, functools.partial)={}'.format(name, isinstance(x, functools.partial)))
def func(a, b):
pass
partial = functools.partial(func, a=1)
_lambda = lambda _: _
def generator():
yield 1
yield 2
async def async_func():
pass
async def async_generator():
yield 1
class A:
def __call__(self, a, b):
pass
def func1(self, a, b):
pass
@classmethod
def func2(cls, a, b):
pass
@staticmethod
def func3(a, b):
pass
for func in [print,
func,
partial,
_lambda,
generator,
async_func,
async_generator,
A,
A.func1,
A.func2,
A.func3]:
judge(func)
结果
print
type(print)=<class 'builtin_function_or_method'>
callable(print)=True
hasattr(print, '__call__')=True
inspect.isfunction(print)=False
inspect.ismethod(print)=False
inspect.isgeneratorfunction(print)=False
inspect.iscoroutinefunction(print)=False
inspect.isasyncgenfunction(print)=False
isinstance(print, typing.Callable)=True
isinstance(print, types.BuiltinFunctionType)=True
isinstance(print, types.BuiltinMethodType)=True
isinstance(print, types.FunctionType)=False
isinstance(print, types.MethodType)=False
isinstance(print, types.LambdaType)=False
isinstance(print, functools.partial)=False
func
type(func)=<class 'function'>
callable(func)=True
hasattr(func, '__call__')=True
inspect.isfunction(func)=True
inspect.ismethod(func)=False
inspect.isgeneratorfunction(func)=False
inspect.iscoroutinefunction(func)=False
inspect.isasyncgenfunction(func)=False
isinstance(func, typing.Callable)=True
isinstance(func, types.BuiltinFunctionType)=False
isinstance(func, types.BuiltinMethodType)=False
isinstance(func, types.FunctionType)=True
isinstance(func, types.MethodType)=False
isinstance(func, types.LambdaType)=True
isinstance(func, functools.partial)=False
functools.partial
type(functools.partial)=<class 'functools.partial'>
callable(functools.partial)=True
hasattr(functools.partial, '__call__')=True
inspect.isfunction(functools.partial)=False
inspect.ismethod(functools.partial)=False
inspect.isgeneratorfunction(functools.partial)=False
inspect.iscoroutinefunction(functools.partial)=False
inspect.isasyncgenfunction(functools.partial)=False
isinstance(functools.partial, typing.Callable)=True
isinstance(functools.partial, types.BuiltinFunctionType)=False
isinstance(functools.partial, types.BuiltinMethodType)=False
isinstance(functools.partial, types.FunctionType)=False
isinstance(functools.partial, types.MethodType)=False
isinstance(functools.partial, types.LambdaType)=False
isinstance(functools.partial, functools.partial)=True
<lambda>
type(<lambda>)=<class 'function'>
callable(<lambda>)=True
hasattr(<lambda>, '__call__')=True
inspect.isfunction(<lambda>)=True
inspect.ismethod(<lambda>)=False
inspect.isgeneratorfunction(<lambda>)=False
inspect.iscoroutinefunction(<lambda>)=False
inspect.isasyncgenfunction(<lambda>)=False
isinstance(<lambda>, typing.Callable)=True
isinstance(<lambda>, types.BuiltinFunctionType)=False
isinstance(<lambda>, types.BuiltinMethodType)=False
isinstance(<lambda>, types.FunctionType)=True
isinstance(<lambda>, types.MethodType)=False
isinstance(<lambda>, types.LambdaType)=True
isinstance(<lambda>, functools.partial)=False
generator
type(generator)=<class 'function'>
callable(generator)=True
hasattr(generator, '__call__')=True
inspect.isfunction(generator)=True
inspect.ismethod(generator)=False
inspect.isgeneratorfunction(generator)=True
inspect.iscoroutinefunction(generator)=False
inspect.isasyncgenfunction(generator)=False
isinstance(generator, typing.Callable)=True
isinstance(generator, types.BuiltinFunctionType)=False
isinstance(generator, types.BuiltinMethodType)=False
isinstance(generator, types.FunctionType)=True
isinstance(generator, types.MethodType)=False
isinstance(generator, types.LambdaType)=True
isinstance(generator, functools.partial)=False
async_func
type(async_func)=<class 'function'>
callable(async_func)=True
hasattr(async_func, '__call__')=True
inspect.isfunction(async_func)=True
inspect.ismethod(async_func)=False
inspect.isgeneratorfunction(async_func)=False
inspect.iscoroutinefunction(async_func)=True
inspect.isasyncgenfunction(async_func)=False
isinstance(async_func, typing.Callable)=True
isinstance(async_func, types.BuiltinFunctionType)=False
isinstance(async_func, types.BuiltinMethodType)=False
isinstance(async_func, types.FunctionType)=True
isinstance(async_func, types.MethodType)=False
isinstance(async_func, types.LambdaType)=True
isinstance(async_func, functools.partial)=False
async_generator
type(async_generator)=<class 'function'>
callable(async_generator)=True
hasattr(async_generator, '__call__')=True
inspect.isfunction(async_generator)=True
inspect.ismethod(async_generator)=False
inspect.isgeneratorfunction(async_generator)=False
inspect.iscoroutinefunction(async_generator)=False
inspect.isasyncgenfunction(async_generator)=True
isinstance(async_generator, typing.Callable)=True
isinstance(async_generator, types.BuiltinFunctionType)=False
isinstance(async_generator, types.BuiltinMethodType)=False
isinstance(async_generator, types.FunctionType)=True
isinstance(async_generator, types.MethodType)=False
isinstance(async_generator, types.LambdaType)=True
isinstance(async_generator, functools.partial)=False
A
type(A)=<class 'type'>
callable(A)=True
hasattr(A, '__call__')=True
inspect.isfunction(A)=False
inspect.ismethod(A)=False
inspect.isgeneratorfunction(A)=False
inspect.iscoroutinefunction(A)=False
inspect.isasyncgenfunction(A)=False
isinstance(A, typing.Callable)=True
isinstance(A, types.BuiltinFunctionType)=False
isinstance(A, types.BuiltinMethodType)=False
isinstance(A, types.FunctionType)=False
isinstance(A, types.MethodType)=False
isinstance(A, types.LambdaType)=False
isinstance(A, functools.partial)=False
func1
type(func1)=<class 'function'>
callable(func1)=True
hasattr(func1, '__call__')=True
inspect.isfunction(func1)=True
inspect.ismethod(func1)=False
inspect.isgeneratorfunction(func1)=False
inspect.iscoroutinefunction(func1)=False
inspect.isasyncgenfunction(func1)=False
isinstance(func1, typing.Callable)=True
isinstance(func1, types.BuiltinFunctionType)=False
isinstance(func1, types.BuiltinMethodType)=False
isinstance(func1, types.FunctionType)=True
isinstance(func1, types.MethodType)=False
isinstance(func1, types.LambdaType)=True
isinstance(func1, functools.partial)=False
func2
type(func2)=<class 'method'>
callable(func2)=True
hasattr(func2, '__call__')=True
inspect.isfunction(func2)=False
inspect.ismethod(func2)=True
inspect.isgeneratorfunction(func2)=False
inspect.iscoroutinefunction(func2)=False
inspect.isasyncgenfunction(func2)=False
isinstance(func2, typing.Callable)=True
isinstance(func2, types.BuiltinFunctionType)=False
isinstance(func2, types.BuiltinMethodType)=False
isinstance(func2, types.FunctionType)=False
isinstance(func2, types.MethodType)=True
isinstance(func2, types.LambdaType)=False
isinstance(func2, functools.partial)=False
func3
type(func3)=<class 'function'>
callable(func3)=True
hasattr(func3, '__call__')=True
inspect.isfunction(func3)=True
inspect.ismethod(func3)=False
inspect.isgeneratorfunction(func3)=False
inspect.iscoroutinefunction(func3)=False
inspect.isasyncgenfunction(func3)=False
isinstance(func3, typing.Callable)=True
isinstance(func3, types.BuiltinFunctionType)=False
isinstance(func3, types.BuiltinMethodType)=False
isinstance(func3, types.FunctionType)=True
isinstance(func3, types.MethodType)=False
isinstance(func3, types.LambdaType)=True
isinstance(func3, functools.partial)=False
对比
判断方法 | callable(x) | hasattr(x, ‘__call__’) | inspect.isfunction(x) | inspect.ismethod(x) | inspect.isgeneratorfunction(x) | inspect.iscoroutinefunction(x) | inspect.isasyncgenfunction(x) | isinstance(x, typing.Callable) | isinstance(x, types.BuiltinFunctionType) | isinstance(x, types.BuiltinMethodType) | isinstance(x, types.FunctionType) | isinstance(x, types.MethodType) | isinstance(x, types.LambdaType) | isinstance(x, functools.partial) |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
√ | √ | × | × | × | × | × | √ | √ | √ | × | × | × | × | |
func | √ | √ | √ | × | × | × | × | √ | × | × | √ | × | √ | × |
functools.partial | √ | √ | × | × | × | × | × | √ | × | × | × | × | × | √ |
<lambda> | √ | √ | √ | × | × | × | × | √ | × | × | √ | × | √ | × |
generator | √ | √ | √ | × | √ | × | × | √ | × | × | √ | × | √ | × |
async_func | √ | √ | √ | × | × | √ | × | √ | × | × | √ | × | √ | × |
async_generator | √ | √ | √ | × | × | × | √ | √ | × | × | √ | × | √ | × |
A | √ | √ | × | × | × | × | × | √ | × | × | × | × | × | × |
func1 | √ | √ | √ | × | × | × | × | √ | × | × | √ | × | √ | × |
func2 | √ | √ | × | √ | × | × | × | √ | × | × | × | √ | × | × |
func3 | √ | √ | √ | × | × | × | × | √ | × | × | √ | × | √ | × |
import types
import inspect
import functools
import typing
def func(a, b):
pass
partial = functools.partial(func, a=1)
_lambda = lambda _: _
def generator():
yield 1
yield 2
async def async_func():
pass
async def async_generator():
yield 1
class A:
def __call__(self, a, b):
pass
def func1(self, a, b):
pass
@classmethod
def func2(cls, a, b):
pass
@staticmethod
def func3(a, b):
pass
def judge(x):
results = [
callable(x),
hasattr(x, '__call__'),
inspect.isfunction(x),
inspect.ismethod(x),
inspect.isgeneratorfunction(x),
inspect.iscoroutinefunction(x),
inspect.isasyncgenfunction(x),
isinstance(x, typing.Callable),
isinstance(x, types.BuiltinFunctionType),
isinstance(x, types.BuiltinMethodType),
isinstance(x, types.FunctionType),
isinstance(x, types.MethodType),
isinstance(x, types.LambdaType),
isinstance(x, functools.partial)
]
return results
funcs = [
print,
func,
partial,
_lambda,
generator,
async_func,
async_generator,
A,
A.func1,
A.func2,
A.func3
]
judge_names = [
'callable(x)',
'hasattr(x, \'__call__\')',
'inspect.isfunction(x)',
'inspect.ismethod(x)',
'inspect.isgeneratorfunction(x)',
'inspect.iscoroutinefunction(x)',
'inspect.isasyncgenfunction(x)',
'isinstance(x, typing.Callable)',
'isinstance(x, types.BuiltinFunctionType)',
'isinstance(x, types.BuiltinMethodType)',
'isinstance(x, types.FunctionType)',
'isinstance(x, types.MethodType)',
'isinstance(x, types.LambdaType)',
'isinstance(x, functools.partial)'
]
print('|判断方法|{}|'.format('|'.join(judge_names)))
print('|--' * (1 + len(judge_names)) + '|')
for x in funcs:
func_name = x.__name__ if hasattr(x, '__name__') else 'functools.partial'
results = judge(x)
results = ['√' if i else '×' for i in results]
print('|{}|{}|'.format(func_name, '|'.join(results)))
耗时
挑选最通用的三种方法:
函数 | 耗时/s |
---|---|
callable(x) | 0.86 |
hasattr(x, ‘__call__’) | 1.36 |
isinstance(x, typing.Callable) | 12.19 |
import typing
from timeit import timeit
def x():
pass
def f1():
return callable(x)
def f2():
return hasattr(x, '__call__')
def f3():
return isinstance(x, typing.Callable)
print(timeit(f1, number=10000000))
print(timeit(f2, number=10000000))
print(timeit(f3, number=10000000))
# 0.8643081
# 1.3563508
# 12.193492500000001