Python判断一个对象是否为函数或方法

文章目录

问题描述

Python判断一个对象是否为函数




解决方案

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)
print × × × × × × × × ×
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




参考文献

  1. How do I detect whether a Python variable is a function?
  2. Python快速计算函数耗时timeit
上一篇:移动端开发在iOS系统中 new Date() 返回 NaN 的问题


下一篇:vue cli 查看webpack的配置