当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何检测Python变量是否为函数?》经验,为你挑选了13个好方法。

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

我希望我可以这样做:

>>> isinstance(x, function)

但这给了我:

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

我选择它的原因是因为

>>> type(x)

John Feminel.. 816

如果这适用于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> John Feminel..:

如果这适用于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除非你对函数的含义有一个非常具体的了解,否则不要使用.


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

2> Ryan..:

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

In [1]: import types
In [2]: types.FunctionType
Out[2]: 
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


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

3> Paolo..:

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

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


请参阅`inspect.isfunction` docstring:*"如果对象是用户定义的函数,则返回true."*
@Zecc [isbuiltin](http://docs.python.org/2/library/inspect.html#inspect.isbuiltin)就是为了这个.
很好,但它似乎为内置函数返回False,如`open`和`hasattr`.
请注意,'isfunction'无法识别functool.partial函数.

4> SingleNegati..:

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


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

5> Nikhil Chell..:

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

callable(x)



6> nh2..:

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

import collections
isinstance(obj, collections.Callable)

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



7> Chris B...:

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)

你会得到 True True作为输出.

isinstance很好地确定某些东西是否是一种功能(尝试isinstance(b, types.FunctionType)); 如果你真的有兴趣知道是否可以调用某些东西,你可以使用hasattr(b, '__call__')或者只是尝试一下.

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

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


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

8> Marcin Wojna..:

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

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

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



9> maxyfc..:

尝试使用callable(x).



10> Sumukh Barve..:

这是另外两种方式:

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

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

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

>>> type(lambda x: x);

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



11> 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比使用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!



12> Kinght 金..:

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

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

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] 
[False, True, False, True, False] 
[False, True, False, True, False]  at 0x7f1b5081fd08>
[False, False, False, False, True] functools.partial(, b=4)
[False, False, False, False, False] <__main__.A object at 0x7f1b50870cc0>
[False, True, False, True, False] 
[False, False, True, False, False] >
[False, True, False, True, False] 
"""

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

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

如:

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



13> Algebra..:

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

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

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

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

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

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

推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有