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

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

>>> isinstance(x, function)

但这给了我:

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

我选这个是因为

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

当前回答

由于类也有__call__方法,我推荐另一种解决方案:

class A(object):
    def __init__(self):
        pass
    def __call__(self):
        print 'I am a Class'

MyClass = A()

def foo():
    pass

print hasattr(foo.__class__, 'func_name') # Returns True
print hasattr(A.__class__, 'func_name')   # Returns False as expected

print hasattr(foo, '__call__') # Returns True
print hasattr(A, '__call__')   # (!) Returns True while it is not a function

其他回答

这里有一些其他的方法:

def isFunction1(f) :
    return type(f) == type(lambda x: x);

def isFunction2(f) :
    return 'function' in str(type(f));

我是这样想到第二个的:

>>> type(lambda x: x);
<type 'function'>
>>> str(type(lambda x: x));
"<type 'function'>"
# Look Maa, function! ... I ACTUALLY told my mom about this!

作为公认的答案,John Feminella说:

检查鸭子类型对象属性的正确方法是询问它们是否嘎嘎叫,而不是查看它们是否适合鸭子大小的容器。“直接比较”的方法会对许多函数给出错误的答案,比如内置函数。

尽管有两个库来严格区分函数,但我画了一个详尽的可比表:

8.9. 内置类型的动态类型创建和名称。Python 3.7.0文档

30.13. inspect -检查活动对象- Python 3.7.0文档

#import inspect             #import types
['isabstract',
 'isasyncgen',              'AsyncGeneratorType',
 'isasyncgenfunction', 
 'isawaitable',
 'isbuiltin',               'BuiltinFunctionType',
                            'BuiltinMethodType',
 'isclass',
 'iscode',                  'CodeType',
 'iscoroutine',             'CoroutineType',
 'iscoroutinefunction',
 'isdatadescriptor',
 'isframe',                 'FrameType',
 'isfunction',              'FunctionType',
                            'LambdaType',
                            'MethodType',
 'isgenerator',             'GeneratorType',
 'isgeneratorfunction',
 'ismethod',
 'ismethoddescriptor',
 'ismodule',                'ModuleType',        
 'isroutine',            
 'istraceback',             'TracebackType'
                            'MappingProxyType',
]

“duck typing”是一般用途的首选解决方案:

def detect_function(obj):
    return hasattr(obj,"__call__")

In [26]: detect_function(detect_function)
Out[26]: True
In [27]: callable(detect_function)
Out[27]: True

至于内置函数

In [43]: callable(hasattr)
Out[43]: True

当进一步检查是内置函数还是用户定义函数

#check inspect.isfunction and type.FunctionType
In [46]: inspect.isfunction(detect_function)
Out[46]: True
In [47]: inspect.isfunction(hasattr)
Out[47]: False
In [48]: isinstance(detect_function, types.FunctionType)
Out[48]: True
In [49]: isinstance(getattr, types.FunctionType)
Out[49]: False
#so they both just applied to judge the user-definded

确定是否内置函数

In [50]: isinstance(getattr, types.BuiltinFunctionType)
Out[50]: True
In [51]: isinstance(detect_function, types.BuiltinFunctionType)
Out[51]: False

总结

采用可调用鸭类型检查函数, 使用类型。如果您有进一步指定的需求,请使用BuiltinFunctionType。

被接受的答案在当时被认为是正确的。因为它 结果是,没有callable()的替代品,这又回到了Python中 3.2:具体来说,callable()检查对象的tp_call字段 测试。在普通的Python中没有对等的。大多数建议的测试都是 大多数时候是正确的:

>>> class Spam(object):
...     def __call__(self):
...         return 'OK'
>>> can_o_spam = Spam()


>>> can_o_spam()
'OK'
>>> callable(can_o_spam)
True
>>> hasattr(can_o_spam, '__call__')
True
>>> import collections
>>> isinstance(can_o_spam, collections.Callable)
True

方法中删除__call__来解决这个问题 类。为了让事情更有趣,在实例中添加一个假__call__ !

>>> del Spam.__call__
>>> can_o_spam.__call__ = lambda *args: 'OK?'

注意这个真的是不可调用的:

>>> can_o_spam()
Traceback (most recent call last):
  ...
TypeError: 'Spam' object is not callable

Callable()返回正确的结果:

>>> callable(can_o_spam)
False

但是hasattr错了:

>>> hasattr(can_o_spam, '__call__')
True

Can_o_spam确实有这个属性;它只是在调用时不使用 实例。

更微妙的是,isinstance()也会出错:

>>> isinstance(can_o_spam, collections.Callable)
True

因为我们之前使用了这个检查,后来删除了方法abc。ABCMeta 缓存结果。可以说这是abc.ABCMeta中的一个bug。也就是说, 没有比这更准确的结果了 结果比使用callable()本身,因为typeobject->tp_call 槽方法不能以任何其他方式访问。

只需使用callable()

如果传递的对象可以在Python中调用,callable(x)将返回true,但该函数在Python 3.0中不存在,正确地说,将不区分:

class A(object):
    def __call__(self):
        return 'Foo'

def B():
    return 'Bar'

a = A()
b = B

print type(a), callable(a)
print type(b), callable(b)

你将得到<class 'A'> True和<type function> True作为输出。

isinstance可以很好地确定某个东西是否是函数(尝试isinstance(b, types.FunctionType));如果你真的想知道某个东西是否可以被调用,你可以使用hasattr(b, '__call__')或直接尝试。

test_as_func = True
try:
    b()
except TypeError:
    test_as_func = False
except:
    pass

当然,这不会告诉您它是可调用的,但在执行时抛出TypeError,还是一开始就不可调用。这对你来说可能无关紧要。

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

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

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