我有一个变量x,我想知道它是否指向一个函数。

我希望我能做一些像这样的事情:

>>> isinstance(x, function)

但这给了我:

Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'function' is not defined

我选这个是因为

>>> type(x)
<type 'function'>

当前回答

使用isinstance()和type(),它们都是Python中的内置函数,你可以检查它是否是一个函数,这样你就不需要导入任何东西:

def test():
    pass

print(isinstance(test, type(test)))

输出:

True

其他回答

结果

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 × × × × × × × × × × ×
meth × × × × × × × ×
classmeth × × × × × × × × ×
staticmeth × × × × × × × ×
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 meth(self, a, b):
        pass

    @classmethod
    def classmeth(cls, a, b):
        pass

    @staticmethod
    def staticmeth(a, b):
        pass


for func in [print,
             func,
             partial,
             _lambda,
             generator,
             async_func,
             async_generator,
             A,
             A.meth,
             A.classmeth,
             A.staticmeth]:
    judge(func)

Time

选择三种最常见的方法:

可调用的(x) hasattr (x, __call__) isinstance (x, typing.Callable)

time/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

注意,Python类也是可调用的。

要获得函数(这里的函数指的是标准函数和lambdas),请使用:

import types

def is_func(obj):
    return isinstance(obj, (types.FunctionType, types.LambdaType))


def f(x):
    return x


assert is_func(f)
assert is_func(lambda x: x)

如果你想检测所有语法上看起来像函数的东西:函数、方法、内置的fun/meth、lambda…但排除可调用对象(定义了__call__方法的对象),然后尝试这个:

import types
isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType))

我将其与inspect模块中的is*()检查代码进行了比较,上面的表达式要完整得多,特别是如果您的目标是过滤任何函数或检测对象的常规属性。

如果值是可调用的,代码将继续执行调用,只需执行调用并捕获TypeError。

def myfunc(x):
  try:
    x()
  except TypeError:
    raise Exception("Not callable")

你可以试试这个:

if obj.__class__.__name__ in ['function', 'builtin_function_or_method']:
    print('probably a function')

或者更奇怪的事情:

if "function" in lower(obj.__class__.__name__):
    print('probably a function')