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

Dan*_*l H 629 python

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

我希望我可以这样做:

>>> isinstance(x, function)
Run Code Online (Sandbox Code Playgroud)

但这给了我:

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

我选择它的原因是因为

>>> type(x)
<type 'function'>
Run Code Online (Sandbox Code Playgroud)

Joh*_*lla 816

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

callable(obj)
Run Code Online (Sandbox Code Playgroud)

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

hasattr(obj, '__call__')
Run Code Online (Sandbox Code Playgroud)

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

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

>>> callable(open)
True
Run Code Online (Sandbox Code Playgroud)

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

  • 这也不会告诉你它是否是一个函数 - 只要它可以被调用. (65认同)
  • "鸭子打字"这个概念使得这个答案更好,例如"只要它的行为像一个函数,它是什么才重要?" (38认同)
  • 取决于申请区分是否重要; 我怀疑你是对的,它不适用于原始问题,但这远非确定. (21认同)
  • 有一些用例,其中可调用函数和函数之间的区别是至关重要的,例如在编写装饰器时(请参阅我对Ryan的回答的评论). (6认同)
  • 类可以附加一个__call__函数.所以这绝对不是区分的好方法.瑞恩的方法更好. (4认同)
  • 有时您必须区分,"给我请求处理程序的函数名称或类名" (4认同)
  • 有时候,鸭子打字有其局限性. (3认同)
  • @staticmethods与instancemethods打破了本页面上的每个答案(截至本文撰写时除外).OP选择这是他的首选回应是明智的. (3认同)

Rya*_*yan 250

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

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
Run Code Online (Sandbox Code Playgroud)

  • 它实际上会为内置函数返回False,例如'open'.所以具体来说你必须使用isinstance(f,(types.FunctionType,types.BuiltinFunctionType)).当然,如果你只想要功能,而不是callables或方法. (47认同)
  • +1回答问题.但是,试图猜测对象是否是一个函数 - 或者即使它是任何可调用对象 - 通常都是错误的.如果没有来自OP的进一步信息,当然很难解除它,但仍然...... (5认同)
  • @ŁukaszKorzybski并且更加谨慎......你还应该检查functools.partial:`isinstance(f,(types.FunctionType,types.BuiltinFunctionType,functools.partial))`或在这种情况下检查`f.func` . (5认同)
  • @bobince,这个用例怎么样:我想写一个装饰器`@ foo`,我可以将它们用作`@ foo`和`@foo(some_parameter)`.然后它需要检查它被调用的内容,例如要装饰的函数(第一种情况)或参数(第二种情况,它需要返回另一个装饰器). (3认同)

Pao*_*olo 87

从Python 2.1开始,您可以isfunctioninspect模块导入.

>>> from inspect import isfunction
>>> def f(): pass
>>> isfunction(f)
True
>>> isfunction(lambda x: x)
True
Run Code Online (Sandbox Code Playgroud)

  • 请参阅`inspect.isfunction` docstring:*"如果对象是用户定义的函数,则返回true."* (12认同)
  • @Zecc [isbuiltin](http://docs.python.org/2/library/inspect.html#inspect.isbuiltin)就是为了这个. (11认同)
  • 很好,但它似乎为内置函数返回False,如`open`和`hasattr`. (3认同)
  • 请注意,'isfunction'无法识别functool.partial函数. (3认同)
  • `isfunction` 的 [整个源代码](https://github.com/python/cpython/blob/00e24cdca422f792b80016287562b6b3bccab239/Lib/inspect.py#L159-L170) 是 `return isinstance(object, types.FunctionType)` 所以它带有[@Ryan的回答](/sf/answers/43746391/)中指出的警告。 (3认同)

Sin*_*ion 69

接受的答案是在提供被认为是正确的时候.事实证明,有无可替代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
Run Code Online (Sandbox Code Playgroud)

我们可以通过__call__从班级中移除一把猴子扳手.只是为了让事情更加令人兴奋,__call__为实例添加假货!

>>> del Spam.__call__
>>> can_o_spam.__call__ = lambda *args: 'OK?'
Run Code Online (Sandbox Code Playgroud)

请注意,这真的不可调用:

>>> can_o_spam()
Traceback (most recent call last):
  ...
TypeError: 'Spam' object is not callable
Run Code Online (Sandbox Code Playgroud)

callable() 返回正确的结果:

>>> callable(can_o_spam)
False
Run Code Online (Sandbox Code Playgroud)

但是hasattr错误的:

>>> hasattr(can_o_spam, '__call__')
True
Run Code Online (Sandbox Code Playgroud)

can_o_spam毕竟确实有这个属性; 它只是在调用实例时才使用.

更加微妙,isinstance()也是错误的:

>>> isinstance(can_o_spam, collections.Callable)
True
Run Code Online (Sandbox Code Playgroud)

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

只是用 callable()

  • 关于`hasattr(o,'__ call __')方法的陷阱的惊人例证以及为什么`callable()`,如果可用的话,是优越的. (4认同)

小智 38

结果

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n
可调用(x)hasattr(x, \'__call__\')检查.isfunction(x)检查.ismethod(x)检查.isgeneratorfunction(x)检查.iscoroutinefunction(x)检查.isasyncgenfunction(x)isinstance(x, 打字.Callable)isinstance(x, types.BuiltinFunctionType)isinstance(x, types.BuiltinMethodType)isinstance(x, 类型.FunctionType)isinstance(x, 类型.MethodType)isinstance(x, 类型.LambdaType)isinstance(x, functools.partial)
打印\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xe2\x88\x9a\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xc3\x97
功能\xe2\x88\x9a\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xe2\x88\x9a\xc3\x97
functools.partial\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xe2\x88\x9a
<拉姆达>\xe2\x88\x9a\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xe2\x88\x9a\xc3\x97
发电机\xe2\x88\x9a\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xe2\x88\x9a\xc3\x97
异步函数\xe2\x88\x9a\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xe2\x88\x9a\xc3\x97
异步生成器\xe2\x88\x9a\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xe2\x88\x9a\xc3\x97
A\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xc3\x97
冰毒\xe2\x88\x9a\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xe2\x88\x9a\xc3\x97
类方法\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97
静态方法\xe2\x88\x9a\xe2\x88\x9a\xe2\x88\x9a\xc3\x97\xc3\x97\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xc3\x97\xe2\x88\x9a\xc3\x97\xe2\x88\x9a\xc3\x97
\n
\n
import types\nimport inspect\nimport functools\nimport typing\n\n\ndef judge(x):\n    name = x.__name__ if hasattr(x, \'__name__\') else \'functools.partial\'\n    print(name)\n    print(\'\\ttype({})={}\'.format(name, type(x)))\n    print(\'\\tcallable({})={}\'.format(name, callable(x)))\n    print(\'\\thasattr({}, \\\'__call__\\\')={}\'.format(name, hasattr(x, \'__call__\')))\n    print()\n    print(\'\\tinspect.isfunction({})={}\'.format(name, inspect.isfunction(x)))\n    print(\'\\tinspect.ismethod({})={}\'.format(name, inspect.ismethod(x)))\n    print(\'\\tinspect.isgeneratorfunction({})={}\'.format(name, inspect.isgeneratorfunction(x)))\n    print(\'\\tinspect.iscoroutinefunction({})={}\'.format(name, inspect.iscoroutinefunction(x)))\n    print(\'\\tinspect.isasyncgenfunction({})={}\'.format(name, inspect.isasyncgenfunction(x)))\n    print()\n    print(\'\\tisinstance({}, typing.Callable)={}\'.format(name, isinstance(x, typing.Callable)))\n    print(\'\\tisinstance({}, types.BuiltinFunctionType)={}\'.format(name, isinstance(x, types.BuiltinFunctionType)))\n    print(\'\\tisinstance({}, types.BuiltinMethodType)={}\'.format(name, isinstance(x, types.BuiltinMethodType)))\n    print(\'\\tisinstance({}, types.FunctionType)={}\'.format(name, isinstance(x, types.FunctionType)))\n    print(\'\\tisinstance({}, types.MethodType)={}\'.format(name, isinstance(x, types.MethodType)))\n    print(\'\\tisinstance({}, types.LambdaType)={}\'.format(name, isinstance(x, types.LambdaType)))\n    print(\'\\tisinstance({}, functools.partial)={}\'.format(name, isinstance(x, functools.partial)))\n\n\ndef func(a, b):\n    pass\n\n\npartial = functools.partial(func, a=1)\n\n_lambda = lambda _: _\n\n\ndef generator():\n    yield 1\n    yield 2\n\n\nasync def async_func():\n    pass\n\n\nasync def async_generator():\n    yield 1\n\n\nclass A:\n    def __call__(self, a, b):\n        pass\n\n    def meth(self, a, b):\n        pass\n\n    @classmethod\n    def classmeth(cls, a, b):\n        pass\n\n    @staticmethod\n    def staticmeth(a, b):\n        pass\n\n\nfor func in [print,\n             func,\n             partial,\n             _lambda,\n             generator,\n             async_func,\n             async_generator,\n             A,\n             A.meth,\n             A.classmeth,\n             A.staticmeth]:\n    judge(func)\n
Run Code Online (Sandbox Code Playgroud)\n

时间

\n

选择最常用的三种方法\xef\xbc\x9a

\n\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
次/秒
可调用(x)0.86
hasattr(x, \'__call__\')1.36
isinstance(x, 打字.Callable)12.19
\n
\n
import typing\nfrom timeit import timeit\n\n\ndef x():\n    pass\n\n\ndef f1():\n    return callable(x)\n\n\ndef f2():\n    return hasattr(x, \'__call__\')\n\n\ndef f3():\n    return isinstance(x, typing.Callable)\n\n\nprint(timeit(f1, number=10000000))\nprint(timeit(f2, number=10000000))\nprint(timeit(f3, number=10000000))\n# 0.8643081\n# 1.3563508\n# 12.193492500000001\n
Run Code Online (Sandbox Code Playgroud)\n


Nik*_*iah 37

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

callable(x)
Run Code Online (Sandbox Code Playgroud)

  • “function”不是关键字或内置类型。函数的类型在“types”模块中定义,如“types.FunctionType” (2认同)

nh2*_*nh2 25

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

import collections
isinstance(obj, collections.Callable)
Run Code Online (Sandbox Code Playgroud)

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


Chr*_* B. 19

callable(x) 如果传递的对象可以在Python中调用,返回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)
Run Code Online (Sandbox Code Playgroud)

你会得到<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
Run Code Online (Sandbox Code Playgroud)

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

  • 打电话给它是一个坏主意.如果它有副作用,或实际做某事但需要很长时间怎么办? (7认同)
  • 使用异常知道它是否可调用是一个很大的问题; 如果它*是*可调用的,但调用它会引发你正在寻找的异常?你们都会默默地忽略错误*并且*误判它是否可以调用.当你使用EAFP时,你真的想避免在尝试中放太多,但是对于这个用例没有办法做到这一点. (4认同)
  • 仅仅因为*你不是在调用它并不意味着它没有被调用.也许你正在派遣. (2认同)

Mar*_*ski 14

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

import types
isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType))
Run Code Online (Sandbox Code Playgroud)

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


max*_*yfc 7

尝试使用callable(x).


Cor*_*man 7

精确功能检查器

\n

callable是一个非常好的解决方案。然而,我想以与约翰·费米内拉相反的方式来对待这个问题。而不是像这样说:

\n
\n

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

\n
\n

我们会这样对待它:

\n
\n

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

\n
\n

我们将如何实施它

\n

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

\n

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

\n

下面是哪些类可以对哪些函数进行分类的表格:

\n

来自 kinght-\xe9\x87\x91 的函数表\n以上函数表由 kinght-\xe9\x87\x91 提供

\n

执行此操作的代码

\n

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

\n
from types import BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType\nfrom functools import partial\n\ndef is_function(obj):\n  return isinstance(obj, (BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType, partial))\n\n#-------------------------------------------------\n\ndef my_func():\n  pass\n\ndef add_both(x, y):\n  return x + y\n\nclass a:\n  def b(self):\n    pass\n\ncheck = [\n\nis_function(lambda x: x + x),\nis_function(my_func),\nis_function(a.b),\nis_function(partial),\nis_function(partial(add_both, 2))\n\n]\n\nprint(check)\n>>> [True, True, True, False, True]\n
Run Code Online (Sandbox Code Playgroud)\n

一个错误是 is_function(partial),因为那是一个类,而不是一个函数,而这正是函数,而不是类。这是供您试用代码的预览。

\n

结论

\n

如果您想通过鸭子类型而不是绝对值来检查对象是否是函数,则 callable(obj)是检查对象是否为函数的首选方法。

\n

我们的自定义is_function(obj),也许经过一些编辑是检查对象是否是函数的首选方法,如果您不将任何可调用类实例计数为函数,而仅将内置函数或使用lambda定义的函数,def部分.

\n

我认为这就是全部了。祝你有美好的一天!

\n


Sum*_*rve 6

这是另外两种方式:

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

def isFunction2(f) :
    return 'function' in str(type(f));
Run Code Online (Sandbox Code Playgroud)

这是我想到的第二种方法:

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


dbr*_*dbr 5

函数只是带有__call__方法的类,因此您可以执行

hasattr(obj, '__call__')
Run Code Online (Sandbox Code Playgroud)

例如:

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

>>> x = 2
>>> hasattr(x, '__call__')
False
Run Code Online (Sandbox Code Playgroud)

这是“最佳”方法,但是根据您为什么需要知道它是否可调用或注释的原因,您可以将其放在try / execpt块中:

try:
    x()
except TypeError:
    print "was not callable"
Run Code Online (Sandbox Code Playgroud)

如果try / except比使用Python更有意义,那是有争议的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!
Run Code Online (Sandbox Code Playgroud)


Kin*_*t 金 5

如果您已经学过C++,则必须熟悉function objectfunctor,意味着可以的任何对象be called as if it is a function

在C ++中, an ordinary function是一个函数对象,一个函数指针也是如此;更一般而言,define的类的对象也是如此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建议使用by @Ryan是更好的选择。

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

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

import functools
import types
import pprint
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

定义函子:

#(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
Run Code Online (Sandbox Code Playgroud)

定义函子列表和类型列表:

## 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]
Run Code Online (Sandbox Code Playgroud)

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

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

"""
functors callable:
[True, True, True, True, True, True, True, True]
"""
Run Code Online (Sandbox Code Playgroud)

判断函子的类型(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>
"""
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明

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

如:

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
Run Code Online (Sandbox Code Playgroud)


Alg*_*bra 5

作为公认的答案,约翰·费米内拉说:

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

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

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',
]
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

至于内建函数

In [43]: callable(hasattr)
Out[43]: True
Run Code Online (Sandbox Code Playgroud)

再走一步检查内置功能或用户定义的功能

#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
Run Code Online (Sandbox Code Playgroud)

确定是否 builtin function

In [50]: isinstance(getattr, types.BuiltinFunctionType)
Out[50]: True
In [51]: isinstance(detect_function, types.BuiltinFunctionType)
Out[51]: False
Run Code Online (Sandbox Code Playgroud)

摘要

采用callable鸭式检查功能,如果您有进一步指定的需求,
请使用types.BuiltinFunctionType