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

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

>>> isinstance(x, function)

但这给了我:

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

我选这个是因为

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

当前回答

如果这是针对Python 2。对于Python 3.2+,可以使用callable()。它曾经被弃用,但现在不弃用了,所以您可以再次使用它。你可以在这里阅读讨论:http://bugs.python.org/issue10518。你可以这样做:

callable(obj)

如果这是针对Python 3。X但在3.2之前,检查对象是否有__call__属性。你可以这样做:

hasattr(obj, '__call__')

经常被提及的类型。函数类型或检查。Isfunction方法(两者做的是完全相同的事情)有一些注意事项。对于非python函数,它返回False。例如,大多数内置函数是用C而不是Python实现的,因此它们返回False:

>>> isinstance(open, types.FunctionType)
False
>>> callable(open)
True

所以类型。FunctionType可能会给您带来令人惊讶的结果。检查鸭子类型对象属性的正确方法是询问它们是否嘎嘎叫,而不是查看它们是否适合鸭子大小的容器。

其他回答

你可以试试这个:

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')

结合@Sumukh Barve, @Katsu和@tinnick的回答,如果你的动机只是想在控制台中获取可用的内置函数列表,这两个选项是可行的:

(我对j __builtin__.__dict__.items如果j.__class__()。__name__ in ['function', 'builtin_function_or_method']] (我对j __builtin__.__dict__.items()如果str (j)(18): = = ' <内置函数)

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

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

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

Python的2to3工具(http://docs.python.org/dev/library/2to3.html)建议:

import collections
isinstance(obj, collections.Callable)

这似乎是选择了hasattr(x, '__call__')方法,因为http://bugs.python.org/issue7006。

结果

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