ChatGPT解决这个技术问题 Extra ChatGPT

如何检测 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'>
我对通过寻找一些调用属性或可调用函数来解决问题的答案数量感到沮丧......一种干净的方法是关于@ryan建议的 type(a) == types.functionType
@AsTeR检查鸭子类型对象的属性的正确方法是询问它们是否嘎嘎,而不是查看它们是否适合鸭子大小的容器。 “直接比较”的方法会为许多函数给出错误的答案,比如内置函数。
@JohnFeminella 虽然我原则上同意你的看法。 OP 没有询问它是否可调用,只是询问它是否是一个函数。也许可以说他需要区分函数和类?
出于我的目的,我来到这里是因为我想在各种对象上使用 insepct.getsource,实际上,对象是否可调用并不重要,而是它是否可以为 type(obj) 提供“功能”。由于谷歌把我带到了这里,我想说 AsTeR 的评论是最有用的答案(对我来说)。互联网上还有很多其他地方可供人们发现 __call__callable
@AsTeR 它是 types.FunctionType,大写 F。

B
Boris Verkhovskiy

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

callable(obj)

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

hasattr(obj, '__call__')

经常建议的 types.FunctionTypesinspect.isfunction 方法(两者都做 the exact same thing)带有许多警告。它为非 Python 函数返回 False。例如,大多数 builtin functions 是用 C 而不是 Python 实现的,因此它们返回 False

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

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


这也不会告诉你它是否是一个函数——只是它是否可以被调用。
区别是否重要取决于应用程序;我怀疑你是对的,它不适用于原始问题,但这远非确定。
类可以附加一个调用函数。所以这绝对不是一个好的区分方法。 Ryan的方法更好。
“鸭子打字”概念使其成为更好的答案,例如“如果它是一个函数,只要它表现得像一个函数有什么关系?”
在某些用例中,可调用函数和函数之间的区别至关重要,例如在编写装饰器时(请参阅我对 Ryan 答案的评论)。
G
Gringo Suave

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

>>> import types
>>> types.FunctionType
<class 'function'>

>>> def f(): pass

>>> isinstance(f, types.FunctionType)
True
>>> isinstance(lambda x : None, types.FunctionType)
True

请注意,这使用了一个非常具体的“功能”概念,这通常不是您所需要的。例如,它拒绝 zip(技术上是一个类):

>>> type(zip), isinstance(zip, types.FunctionType)
(<class 'type'>, False)

open(内置函数有不同的类型):

>>> type(open), isinstance(open, types.FunctionType)
(<class 'builtin_function_or_method'>, False)

random.shuffle(技术上是隐藏 random.Random 实例的方法):

>>> type(random.shuffle), isinstance(random.shuffle, types.FunctionType)
(<class 'method'>, False)

如果您正在执行特定于 types.FunctionType 实例的操作,例如反编译其字节码或检查闭包变量,请使用 types.FunctionType,但如果您只需要像函数一样可调用的对象,请使用 callable


+1 回答问题。然而,试图猜测一个对象是否是一个函数——或者即使它是任何可调用的对象——通常都是错误的。如果没有来自 OP 的进一步信息,当然很难将其排除在外,但仍然......
它实际上会为内置函数返回 False,例如 'open' 。因此,具体而言,您必须使用 isinstance(f, (types.FunctionType, types.BuiltinFunctionType))。当然,如果您只需要函数,而不是可调用对象或方法。
@ŁukaszKorzybski 更准确地说……在这种情况下,您还应该检查 functools.partial: isinstance(f, (types.FunctionType, types.BuiltinFunctionType, functools.partial)) 或检查 f.func
@bobince,这个用例怎么样:我想编写一个装饰器 @foo,我可以将它用作 @foo@foo(some_parameter)。然后它需要检查它被调用的是什么,例如要装饰的函数(第一种情况)或参数(第二种情况,它需要返回一个进一步的装饰器)。
types.BuiltinFunctionType 也是(“正常”)内置方法 的类型,如果您不采用 callable 路线,您可能不希望允许这种类型。
V
Vebjorn Ljosa

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

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

不错,但对于 openhasattr 等内置函数,它似乎返回 False。
@Zecc isbuiltin 就是为此。
请参阅 inspect.isfunction 文档字符串:“如果对象是用户定义的函数,则返回 true。”
请注意,“isfunction”不能识别 functool.partial 函数。
isfunctionentire source codereturn isinstance(object, types.FunctionType),因此它带有 @Ryan's answer 中指出的注意事项。
P
Peter Mortensen

接受的答案是在被提供时被认为是正确的。事实证明,没有替代可以替代 Python 3.2 中的 callable():具体来说,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()


hasattr(o, '__call__') 方法的缺陷以及为什么 callable()(如果可用)更胜一筹的惊人说明。
N
Nikhil

以下应返回一个布尔值:

callable(x)

这解决了他的问题,但他仍然创造了一个谜:如果 x 是内置模块中的类“函数”,并且 help(x.__class__) 描述了“类函数”,为什么“函数”显然是“未定义”?
“函数”不是关键字或内置类型。函数的类型在“types”模块中定义为“types.FunctionType”
G
Gary van der Merwe

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

import collections
isinstance(obj, collections.Callable)

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


错误报告中也提到了为 py3.3 带回 callable()bugs.python.org/issue10518#msg122309
X
XerCis

结果

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) 打印 √ √ × × × × × √ √ √ × × × × func √ √ √ × × × × √ × × √ × √ × functools.partial √ √ × × × × × √ × × × × √ √ √ √ × × × × √ × × √ × √ × generator √ √ √ × √ × × √ × × √ × √ × async_func √ √ √ × × √ × √ × × √ × √ × async_generator √ √ √ × × × √ √ × × √ × √ × A √ √ × × × × × √ × × × × × × func1 √ √ √ × × × × √ × × √ × √ × func2 √ √ × √ × × × √ × × × √ × × func3 √ √ √ × × × × √ × × √ × √ ×

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 func1(self, a, b):
        pass

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

    @staticmethod
    def func3(a, b):
        pass


for func in [print,
             func,
             partial,
             _lambda,
             generator,
             async_func,
             async_generator,
             A,
             A.func1,
             A.func2,
             A.func3]:
    judge(func)

时间

挑选最常用的三种方法:

可调用(x)

hasattr(x, '__call__')

isinstance(x,打字。可调用)

时间/秒 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

美丽的崩溃!应该很容易成为最佳答案:)
C
Chris B.

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

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,或者一开始就不可调用。这对你来说可能无关紧要。


调用它是一个坏主意。如果它有副作用,或者确实做了一些事情但需要很长时间怎么办?
@asmeurer - 如果你不调用它,你为什么还需要知道它是否是一个函数?
@detly:为了调试,我经常想打印对象中的所有变量,这些方法通常对我没有用,所以我不想执行它们。最后,我只列出了每个不可调用的属性以及相应的值:)
仅仅因为你没有调用它并不意味着它没有被调用。也许你在做调度。
使用异常来判断它是否可调用存在很大的问题;如果它是可调用的,但调用它会引发您正在寻找的异常怎么办?你会默默地忽略错误并误诊它是否可调用。当您使用 EAFP 时,您确实希望避免在尝试中投入太多,但是对于这个用例,没有办法做到这一点。
M
Marcin Wojnarski

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

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

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


感谢您将我指向 types 模块。我正在测试一个 make_stemmer() 工厂,它有时会返回一个函数,有时会返回一个可调用的 Stemmer 实例,我需要检测其中的差异。
m
maxyfc

尝试使用 callable(x)


C
Community

如果您学过 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.

如果你想判断天气对象的行为就像一个函数,那么@John Feminella 建议的可调用方法就可以了。如果要判断一个对象是否只是一个普通函数(不是可调用的类实例,也不是 lambda 表达式),那么@Ryan 建议的 xtypes.XXX 是更好的选择。

然后我使用这些代码做一个实验:

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

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

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>
"""

我使用数据绘制了一张可调用函子类型的表格。

https://i.stack.imgur.com/W3Hvi.png

然后你可以选择合适的函子类型。

如:

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

A
AbstProcDo

作为公认的答案,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


p
pb2q

以下是其他几种方法:

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!

这很好!应该适用于所有版本的 python2.x 和 python3.x!
C
Community

精确的功能检查器

callable 是一个很好的解决方案。然而,我想以与 John Feminella 相反的方式来对待这个问题。而不是这样对待它:

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

我们会这样对待它:

判断一个东西是不是鸭子的正确方法不是看它会不会嘎嘎叫,而是通过几个过滤器来看看它是否真的是鸭子,而不是仅仅从表面上看它是否像鸭子。

我们将如何实现它

'types' 模块有很多类来检测函数,最有用的是 types.FunctionType,但也有很多其他的,比如方法类型、内置类型和 lambda 类型。我们还将把 'functools.partial' 对象视为一个函数。

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

下表列出了哪些类可以对哪些功能进行分类:

https://i.stack.imgur.com/W3Hvi.png

执行它的代码

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

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) 是检查对象是否为函数的首选方法,如果您想通过鸭式键入绝对值。

我们的自定义 is_function(obj),如果您不将可调用类实例计数为函数,但仅将函数定义为内置或使用 lambda、def ,或部分。

我认为这一切都结束了。祝你有美好的一天!


d
dbr

函数只是具有 __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() 更 Python'y,这是有争议的。我会说 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!

仅使用异常处理来防止意外行为,从不用于逻辑流——这绝对不是 Pythonic。
好吧,hasattr 基本上在 try/except 块中执行 getattr(尽管在 C 中)。 blog.jancewicz.net/2007/10/reflection-hasattr.html
@dbr:但是 hasattr 更美观。
S
Stefan van den Akker

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

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

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

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

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


g
guneysus

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

同意您的回答,John Feminella 的回答 hasattr(obj, '__call__') 含糊不清。
Ł
Łukasz Rogalski

请注意,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)

K
Katsu

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


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

G
Gerald Senarclens de Grancy

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

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


d
dandan78

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


t
tinnick

你可以试试这个:

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

r
r_hudson

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

[i for i, j in __builtin__.__dict__.items() if j.__class__.__name__ in ['function', 'builtin_function_or_method']] [i for i, j in __builtin__.__dict__.items() if str(j) [:18] == '<内置函数']


J
Jabba

根据之前的回复,我想出了这个:

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)

R
Roger Dahl

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

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

这是危险的;你不知道 x 有什么副作用。
P
Peter Mortensen

以下是检查它的“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

J
Josh Lee

这对我有用:

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

如果结果是空字符串,这告诉我们什么?对于一个函数,我得到 "<type 'function'>",对于一个整数,我得到 "<type 'int'>",所以我看不出它是如何为你工作的:/
现在仅适用于 Python 3 :) 另外,根据问题的初衷,它是不完整的:内置 open 是否应该被视为一个函数? str(type(open)) 在 Python 3 中给出 <class 'builtin_function_or_method'>
p
phnghue

您可以DIY一个简短的函数来检查输入是否不是字符串并将输入转换为字符串将返回匹配的名称定义:

def isFunction(o):return not isinstance(o,str) and str(o)[:3]=='<fu';

我认为这段代码已经兼容所有 python 版本。

或者,如果发生变化,您可以添加额外的小写转换并检查内容长度。我看到的函数的格式字符串是“