如何检测Python变量是否为函数?

时间:2009-03-09 03:31:31

标签: python

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

我曾希望我可以这样做:

>>> isinstance(x, function)

但这给了我:

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

我选择它的原因是因为

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

26 个答案:

答案 0 :(得分:750)

如果是针对Python 2.x或Python 3.2+,您也可以使用callable()。它曾经被弃用,但现在已经过时,所以你可以再次使用它。您可以在此处阅读讨论:http://bugs.python.org/issue10518。你可以这样做:

callable(obj)

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

hasattr(obj, '__call__')

经常提出的types.FunctionTypes方法不正确,因为它无法涵盖您可能希望它通过的许多情况,例如内置:

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

>>> callable(open)
True

检查鸭子类型物体属性的正确方法是询问它们是否嘎嘎叫,而不是看它们是否适合鸭子大小的容器。不要使用types.FunctionType,除非您对函数的含义有非常具体的了解。

答案 1 :(得分:240)

内置命名空间中没有构造函数的内置类型(例如函数,生成器,方法)位于types模块中。您可以在isinstance调用中使用types.FunctionType

In [1]: import types
In [2]: types.FunctionType
Out[2]: <type 'function'>
In [3]: def f(): pass
   ...:
In [4]: isinstance(f, types.FunctionType)
Out[4]: True
In [5]: isinstance(lambda x : None, types.FunctionType)
Out[5]: True

答案 2 :(得分:84)

Since Python 2.1您可以从inspect模块导入isfunction

>>> from inspect import isfunction
>>> def f(): pass
>>> isfunction(f)
True
>>> isfunction(lambda x: x)
True

答案 3 :(得分:64)

接受的答案是在提供被认为是正确的时候。就这样 事实证明,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中的一个错误。那说, 实际上没有可能 产生更准确的结果 结果而不是使用callable()本身,因为typeobject->tp_call 无法以任何其他方式访问slot方法。

只需使用callable()

即可

答案 4 :(得分:35)

以下内容应返回布尔值:

callable(x)

答案 5 :(得分:24)

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

import collections
isinstance(obj, collections.Callable)

由于http://bugs.python.org/issue7006,似乎选择了这个而不是hasattr(x, '__call__')方法。

答案 6 :(得分:19)

如果传递的对象可以在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可以很好地确定某些内容是否为函数(try isinstance(b, types.FunctionType));如果你真的想知道是否可以调用某些内容,你可以使用hasattr(b, '__call__')或者只是尝试它。

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

当然,这不会告诉您它是否可调用但在执行时会抛出TypeError,或者首先不可调用。这对你来说可能无关紧要。

答案 7 :(得分:13)

如果要检测语法上看起来像函数的所有内容:函数,方法,内置fun / meth,lambda ......但排除可调用对象({{1}的对象}方法定义),然后尝试这个:

__call__

我将此与import types isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType)) 模块中的is*()检查代码进行了比较,上面的表达式更为完整,特别是如果您的目标是过滤掉任何函数或检测对象的常规属性。 / p>

答案 8 :(得分:6)

尝试使用callable(x)

答案 9 :(得分:5)

函数只是一个带__call__方法的类,所以你可以做

hasattr(obj, '__call__')

例如:

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

>>> x = 2
>>> hasattr(x, '__call__')
False

这是“最好”的方式,但是根据你需要知道它是否可以调用或注释的原因,你可以把它放在try / execpt块中:

try:
    x()
except TypeError:
    print "was not callable"

如果try / except比执行if hasattr(x, '__call__'): x()更狡猾,那是有争议的。我会说hasattr更准确,因为你不会意外地捕获错误的TypeError,例如:

>>> def x():
...     raise TypeError
... 
>>> hasattr(x, '__call__')
True # Correct
>>> try:
...     x()
... except TypeError:
...     print "x was not callable"
... 
x was not callable # Wrong!

答案 10 :(得分:5)

以下是其他几种方式:

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!

答案 11 :(得分:5)

如果您已经了解C++,则必须熟悉function objectfunctor,表示任何可以be called as if it is a function的对象。

在C ++中,an ordinary function是一个函数对象,函数指针也是如此;更一般地说,定义operator()的类的对象也是如此。在C ++ 11及更高版本中,the lambda expression也是functor

相似性,在Python中,那些functors都是callableAn ordinary function可以调用,a lambda expression可以调用,functional.partial可以调用,class with a __call__() method的实例可以调用。

好的,回到问题:I have a variable, x, and I want to know whether it is pointing to a function or not.

  

如果您想判断天气,该对象就像一个函数,那么callable建议的@John Feminella方法就可以了。

     

如果你想要judge whether a object is just an ordinary function or not(不是可调用的类实例或lambda表达式),那么xtypes.XXX建议的@Ryan是更好的选择。

然后我使用这些代码进行实验:

#!/usr/bin/python3
# 2017.12.10 14:25:01 CST
# 2017.12.10 15:54:19 CST

import functools
import types
import pprint
  

定义一个类和一个普通函数。

class A():
    def __call__(self, a,b):
        print(a,b)
    def func1(self, a, b):
        print("[classfunction]:", a, b)
    @classmethod
    def func2(cls, a,b):
        print("[classmethod]:", a, b)
    @staticmethod
    def func3(a,b):
        print("[staticmethod]:", a, b)

def func(a,b):
    print("[function]", a,b)
  

定义仿函数:

#(1.1) built-in function
builtins_func = open
#(1.2) ordinary function
ordinary_func = func
#(1.3) lambda expression
lambda_func  = lambda a : func(a,4)
#(1.4) functools.partial
partial_func = functools.partial(func, b=4)

#(2.1) callable class instance
class_callable_instance = A()
#(2.2) ordinary class function
class_ordinary_func = A.func1
#(2.3) bound class method
class_bound_method = A.func2
#(2.4) static class method
class_static_func = A.func3
  

定义仿函数&#39;列表和类型&#39;列表:

## list of functors
xfuncs = [builtins_func, ordinary_func, lambda_func, partial_func, class_callable_instance, class_ordinary_func, class_bound_method, class_static_func]
## list of type
xtypes = [types.BuiltinFunctionType, types.FunctionType, types.MethodType, types.LambdaType, functools.partial]
  

判断仿函数是否可以调用。如你所见,它们都是可调用的。

res = [callable(xfunc)  for xfunc in xfuncs]
print("functors callable:")
print(res)

"""
functors callable:
[True, True, True, True, True, True, True, True]
"""
  

判断仿函数的类型(types.XXX)。然后,仿函数的类型并不完全相同。

res = [[isinstance(xfunc, xtype) for xtype in xtypes] for xfunc in xfuncs]

## output the result
print("functors' types")
for (row, xfunc) in zip(res, xfuncs):
    print(row, xfunc)

"""
functors' types
[True, False, False, False, False] <built-in function open>
[False, True, False, True, False] <function func at 0x7f1b5203e048>
[False, True, False, True, False] <function <lambda> at 0x7f1b5081fd08>
[False, False, False, False, True] functools.partial(<function func at 0x7f1b5203e048>, b=4)
[False, False, False, False, False] <__main__.A object at 0x7f1b50870cc0>
[False, True, False, True, False] <function A.func1 at 0x7f1b5081fb70>
[False, False, True, False, False] <bound method A.func2 of <class '__main__.A'>>
[False, True, False, True, False] <function A.func3 at 0x7f1b5081fc80>
"""

我使用数据绘制了一个可调用仿函数类型的表。

enter image description here

  

然后你可以选择仿函数&#39;适合的类型。

如:

def func(a,b):
    print("[function]", a,b)

>>> callable(func)
True
>>> isinstance(func,  types.FunctionType)
True
>>> isinstance(func, (types.BuiltinFunctionType, types.FunctionType, functools.partial))
True
>>> 
>>> isinstance(func, (types.MethodType, functools.partial))
False

答案 12 :(得分:4)

由于类也有__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

答案 13 :(得分:4)

请注意,Python类也可以调用。

要获取函数(以及函数,我们指的是标准函数和lambda),请使用:

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)

答案 14 :(得分:4)

约翰·费米内拉(John Feminella)作为公认的答案说:

  

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

尽管有两个库严格区分功能,但我还是绘制了一个详尽的可比较表:

8.9. types — Dynamic type creation and names for built-in types — Python 3.7.0 documentation

30.13. inspect — Inspect live objects — Python 3.7.0 documentation

#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',
]

“鸭子打字”是通用的首选解决方案:

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

确定是否builtin function

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

摘要

使用callable进行类型检查功能,
如果您进一步指定了需求,请使用types.BuiltinFunctionType

答案 15 :(得分:3)

您可以检查用户定义的函数是否具有属性'__call__'func_name等,而不是检查func_doc(不是函数专用)。这不起作用方法。

>>> def x(): pass
... 
>>> hasattr(x, 'func_name')
True

另一种检查方法是使用isfunction()模块中的inspect方法。

>>> import inspect
>>> inspect.isfunction(x)
True

要检查对象是否为方法,请使用inspect.ismethod()

答案 16 :(得分:2)

无论函数是什么类,因此您可以获取实例x的类的名称并进行比较:


if(x.__class__.__name__ == 'function'):
     print "it's a function"

答案 17 :(得分:2)

在一些答案中提到的使用hasattr(obj, '__call__')callable(.)的解决方案有一个主要缺点:两者都使用True方法返回类的__call__()类和实例。例如

>>> import collections
>>> Test = collections.namedtuple('Test', [])
>>> callable(Test)
True
>>> hasattr(Test, '__call__')
True

检查对象是否是用户定义的函数(除了那个)之外的一种正确方法是使用isfunction(.)

>>> import inspect
>>> inspect.isfunction(Test)
False
>>> def t(): pass
>>> inspect.isfunction(t)
True

如果您需要检查其他类型,请查看inspect — Inspect live objects

答案 18 :(得分:2)

确切的功能检查器

可通话是一个很好的解决方案。但是,我想以相反的方式对待约翰·费米内拉。而不是像这样说:

  

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

我们将这样处理:

  

检查某物是否为鸭子的正确方法不是通过若干过滤器查看它是否会发出嘎嘎声,而是通过多种过滤器查看它是否确实是鸭子,而不仅仅是从表面上检查它是否看起来像鸭子。

我们将如何实施

“类型”模块具有许多用于检测函数的类,其中最有用的是 types.FunctionType ,但还有许多其他类,例如方法类型,内置类型和Lambda类型。我们还将“ functools.partial”对象视为函数。

我们检查所有类型是否简单的简单方法是使用isinstance条件。以前,我想创建一个从上述所有类继承的基类,但是我无法做到这一点,因为Python不允许我们从上述某些类继承。

这是一张表,其中列出了哪些类可以对哪些函数进行分类:

Functions table from kinght-金 在kinght-金上的功能表上

执行该操作的代码

现在,这是完成我们上面描述的所有工作的代码。

from types import BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType
from functools import partial

def is_function(obj):
  return isinstance(obj, (BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType, partial))

#-------------------------------------------------

def my_func():
  pass

def add_both(x, y):
  return x + y

class a:
  def b(self):
    pass

check = [

is_function(lambda x: x + x),
is_function(my_func),
is_function(a.b),
is_function(partial),
is_function(partial(add_both, 2))

]

print(check)
>>> [True, True, True, False, True]

一个错误是is_function(partial),因为那是一个类,而不是一个函数,而这恰好是函数,而不是类。这是preview,供您尝试使用其中的代码。

结论

callable(obj)是检查对象是否为函数的首选方法,如果您想通过 duck-typing 而不是 absolutes >。

我们的自定义 is_function(obj),如果您不将可调用的类实例视为函数,而仅将函数视为函数,则可能首选进行一些编辑来检查对象是否为函数定义为内置 lambda def partial

我认为这一切都包含在内。祝你有美好的一天!

答案 19 :(得分:1)

在Python3中,我提出了type (f) == type (lambda x:x),如果True是函数,则会产生f,如果不是False,则产生isinstance (f, types.FunctionType)。但我认为我更喜欢type (f) is function,感觉不那么特别。我想做{{1}},但这不起作用。

答案 20 :(得分:0)

结合@Sumukh Barve、@Katsu 和@tinnick 的答案,如果您的动机只是获取可供您在控制台中使用的内置函数列表,那么这两个选项有效:

  1. [i for i, j in __builtin__.__dict__.items() if j.__class__.__name__ in ['function', 'builtin_function_or_method']]
  2. [i for i, j in __builtin__.__dict__.items() if str(j)[:18] == '<built-in function']

答案 21 :(得分:0)

您可以尝试以下方法:

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

答案 22 :(得分:0)

以下是检查它的“repr方式”。它也适用于lambda。

def a():pass
type(a) #<class 'function'>
str(type(a))=="<class 'function'>" #True

b = lambda x:x*2
str(type(b))=="<class 'function'>" #True

答案 23 :(得分:0)

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

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

答案 24 :(得分:0)

根据之前的回复,我提出了这个问题:

from pprint import pprint

def print_callables_of(obj):
    li = []
    for name in dir(obj):
        attr = getattr(obj, name)
        if hasattr(attr, '__call__'):
            li.append(name)
    pprint(li)

答案 25 :(得分:-1)

这对我有用:

str(type(a))=="<class 'function'>"