How do I detect whether a Python variable is a function?
我有一个变量,
我曾希望我能做点什么,比如:
1 | >>> isinstance(x, function) |
但这给了我:
1 2 3 | Traceback (most recent call last): File"<stdin>", line 1, in ? NameError: name 'function' is not defined |
我选择的原因是
1 2 | >>> type(x) <type 'function'> |
如果这是针对python 2.x或python 3.2+,您也可以使用
1 | callable(obj) |
如果这是针对python 3.x的,但在3.2之前,请检查对象是否具有
1 | hasattr(obj, '__call__') |
OFT建议的
1 2 3 4 5 | >>> isinstance(open, types.FunctionType) False >>> callable(open) True |
检查鸭子类型物体属性的正确方法是询问它们是否嘎嘎叫,而不是看它们是否适合鸭子大小的容器。不要使用
内置命名空间中没有构造函数的内置类型(例如函数、生成器、方法)位于
1 2 3 4 5 6 7 8 9 | 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 |
由于python 2.1,您可以从
1 2 3 4 5 6 | >>> from inspect import isfunction >>> def f(): pass >>> isfunction(f) True >>> isfunction(lambda x: x) True |
被接受的答案在提出时被认为是正确的。作为它事实证明,没有替代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | >>> 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 |
我们可以通过从班级。为了让事情更加令人兴奋,在实例中添加一个假的
1 2 | >>> del Spam.__call__ >>> can_o_spam.__call__ = lambda *args: 'OK?' |
注意,这是不可调用的:
1 2 3 4 | >>> can_o_spam() Traceback (most recent call last): ... TypeError: 'Spam' object is not callable |
1 2 | >>> callable(can_o_spam) False |
但
1 2 | >>> hasattr(can_o_spam, '__call__') True |
更微妙的是,
1 2 | >>> isinstance(can_o_spam, collections.Callable) True |
因为我们之前和之后都使用了这种检查方法,所以删除了
只需使用EDOCX1[0]
以下应返回布尔值:
1 | callable(x) |
python的2to3工具(http://docs.python.org/dev/library/2to3.html)建议:
1 2 | import collections isinstance(obj, collections.Callable) |
由于http://bugs.python.org/issue7006,似乎选择了这个方法而不是
如果传递的对象可以在python中调用,但该函数在python 3.0中不存在,则
1 2 3 4 5 6 7 8 9 10 11 12 | 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) |
你将得到
1 2 3 4 5 6 7 | test_as_func = True try: b() except TypeError: test_as_func = False except: pass |
当然,这不会告诉你它是可调用的,但会在执行时抛出一个
如果您想检测语法上看起来像函数的所有东西:函数、方法、内置的fun/meth、lambda…但排除可调用对象(定义了
1 2 | import types isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType)) |
我将它与
尝试使用
以下是其他几种方法:
1 2 3 4 5 | def isFunction1(f) : return type(f) == type(lambda x: x); def isFunction2(f) : return 'function' in str(type(f)); |
下面是我提出第二个问题的方法:
1 2 3 4 5 | >>> type(lambda x: x); <type 'function'> >>> str(type(lambda x: x)); "<type 'function'>" # Look Maa, function! ... I ACTUALLY told my mom about this! |
注意,python类也可以调用。
要获取函数(按函数,我们是指标准函数和lambda),请使用:
1 2 3 4 5 6 7 8 9 10 11 12 | 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) |
如果你学过
在C++中,EDCOX1×25是一个函数对象,函数指针也是如此;更一般地说,定义EDCOX1×26的类的对象也是如此。在C++ 11和更大的情况下,EDCOX1×27是EDCOX1,23也是如此。
在python中,这些
好吧,回到问题上来:
If you want to judge weather the object acts like a function, then the
callable method suggested by@John Feminella is ok.If you want to
judge whether a object is just an ordinary function or not ( not a callable class instance, or a lambda expression), then thextypes.XXX suggested by@Ryan is a better choice.
然后我用这些代码做了一个实验:
1 2 3 4 5 6 7 | #!/usr/bin/python3 # 2017.12.10 14:25:01 CST # 2017.12.10 15:54:19 CST import functools import types import pprint |
Define a class and an ordinary function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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) |
Define the functors:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #(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 |
Define the functors' list and the types' list:
1 2 3 4 | ## 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] |
Judge wether the functor is callable. As you can see, they all are callable.
1 2 3 4 5 6 7 8 | res = [callable(xfunc) for xfunc in xfuncs] print("functors callable:") print(res) """ functors callable: [True, True, True, True, True, True, True, True] """ |
Judge the functor's type( types.XXX). Then the types of functors are not all the same.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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> """ |
我用这些数据绘制了一个可调用函数类型表。
Then you can choose the functors' types that suitable.
例如:
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
函数只是一个带有
1 | hasattr(obj, '__call__') |
例如:
1 2 3 4 5 6 | >>> hasattr(x, '__call__') True >>> x = 2 >>> hasattr(x, '__call__') False |
这是最好的方法,但是根据您需要知道它是可调用的还是可注释的原因,您可以将它放在一个try/execpt块中:
1 2 3 4 | try: x() except TypeError: print"was not callable" |
如果Try/Except比
1 2 3 4 5 6 7 8 9 10 11 | >>> def x(): ... raise TypeError ... >>> hasattr(x, '__call__') True # Correct >>> try: ... x() ... except TypeError: ... print"x was not callable" ... x was not callable # Wrong! |
因为类也有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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指出:
The proper way to check properties of duck-typed objects is to ask them if they quack, not to see if they fit in a duck-sized container. The"compare it directly" approach will give the wrong answer for many functions, like builtins.
尽管有两个libs可以严格区分函数,但我还是绘制了一个详尽的可比表:
8.9。类型-内置类型的动态类型创建和名称-python 3.7.0文档
30.13。检查-检查活动对象-python 3.7.0文档
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #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', ] |
"duck typing"是通用的首选解决方案:
1 2 3 4 5 6 7 | 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 |
至于内置功能
1 2 | In [43]: callable(hasattr) Out[43]: True |
当执行另一步以检查内置函数或用户定义函数时
1 2 3 4 5 6 7 8 9 10 | #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 |
确定
1 2 3 4 | In [50]: isinstance(getattr, types.BuiltinFunctionType) Out[50]: True In [51]: isinstance(detect_function, types.BuiltinFunctionType) Out[51]: False |
总结
使用
您可以检查用户定义的函数是否具有
1 2 3 4 | >>> def x(): pass ... >>> hasattr(x, 'func_name') True |
另一种检查方法是使用来自
1 2 3 | >>> import inspect >>> inspect.isfunction(x) True |
要检查对象是否为方法,请使用
任何函数都是类,因此您可以使用实例x的类的名称并进行比较:
1 2 | if(x.__class__.__name__ == 'function'): print"it's a function" |
一些答案中提到的使用
1 2 3 4 5 6 | >>> import collections >>> Test = collections.namedtuple('Test', []) >>> callable(Test) True >>> hasattr(Test, '__call__') True |
检查一个对象是否是用户定义的函数的一种正确方法是使用
1 2 3 4 5 6 | >>> import inspect >>> inspect.isfunction(Test) False >>> def t(): pass >>> inspect.isfunction(t) True |
如果您需要检查其他类型,请查看inspect-inspect活动对象。
在python3中,我提出了
如果代码继续执行调用,如果值是可调用的,只需执行调用并捕获
1 2 3 4 5 | def myfunc(x): try: x() except TypeError: raise Exception("Not callable") |
下面是一个"repr方法"来检查它。它也与lambda一起工作。
1 2 3 4 5 6 | 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 2 3 4 5 6 7 8 9 | 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) |