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

问题描述 投票:567回答:23

我有一个变量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
23个回答
759
投票

如果这适用于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,除非你对函数是什么有一个非常具体的想法。


5
投票

函数只是一个带有callable(x)方法的类,所以你可以这样做

__call__

例如:

hasattr(obj, '__call__')

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

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

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

如果try / except比使用try: x() except TypeError: print "was not callable" 更狡猾是有争议的..我会说if hasattr(x, '__call__'): x()更准确,因为你不会意外地捕获错误的TypeError,例如:

hasattr

5
投票

以下是其他几种方式:

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

这是我如何想出第二个:

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

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

5
投票

如果你已经学会了>>> type(lambda x: x); <type 'function'> >>> str(type(lambda x: x)); "<type 'function'>" # Look Maa, function! ... I ACTUALLY told my mom about this! ,你必须熟悉C++function object,意思是任何可以functor的物体。

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

相似,在Python中,那些functor都是functorscallable可以调用,An 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(不是可调用的类实例,或lambda表达式),那么judge whether a object is just an ordinary function or not建议的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

判断函子可以调用。如您所见,它们都是可调用的。

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

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

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

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

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

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

4
投票

由于类也有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 方法,我建议另一种解决方案:

__call__

4
投票

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

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

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

4
投票

作为公认的答案,John Feminella表示:

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

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

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)

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


3
投票

您可以检查用户定义的函数是否具有types.BuiltinFunctionType'__call__'等属性,而不是检查func_name(函数不是唯一的)。这不适用于方法。

func_doc

另一种检查方法是使用>>> def x(): pass ... >>> hasattr(x, 'func_name') True 模块中的isfunction()方法。

inspect

要检查对象是否是方法,请使用>>> import inspect >>> inspect.isfunction(x) True


2
投票

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

inspect.ismethod()

2
投票

在一些答案中提到的使用 if(x.__class__.__name__ == 'function'): print "it's a function" 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


1
投票

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


242
投票

在内置命名空间中没有构造函数的内置类型(例如函数,生成器,方法)位于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

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)

0
投票

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

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

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

-1
投票

这对我有用:

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

85
投票

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

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

65
投票

接受的答案是在提供被认为是正确的时候。事实证明,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插槽方法无法以任何其他方式访问。

只需使用callable()


35
投票

以下应该返回一个布尔值:

callable(x)

24
投票

Python 2to3工具(qazxsw poi)建议:

http://docs.python.org/dev/library/2to3.html

由于import collections isinstance(obj, collections.Callable) ,似乎选择了这个而不是hasattr(x, '__call__')方法。


19
投票

如果传递的对象可以在Python中调用,则http://bugs.python.org/issue7006将返回true,但该函数在Python 3.0中不存在,并且正确地说不会区分:

callable(x)

你会得到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 ,或者首先不可调用。这对你来说可能无关紧要。


13
投票

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

__call__

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


6
投票

尝试使用inspect

© www.soinside.com 2019 - 2024. All rights reserved.