如何检测Python变量是否为函数?
我有一个变量,如何检测Python变量是否为函数?,python,Python,我有一个变量,x,我想知道它是否指向函数 我曾希望我能做一些类似的事情: >>> isinstance(x, function) 但这给了我: 回溯(最近一次呼叫最后一次): 文件“”,第1行,是否在中? NameError:未定义名称“函数” 我之所以选择它是因为 >>> type(x) <type 'function'> >类型(x) 以下内容应返回布尔值: callable(x) 尝试使用callable(x)如果这是针对Python
x
,我想知道它是否指向函数
我曾希望我能做一些类似的事情:
>>> isinstance(x, function)
但这给了我:
回溯(最近一次呼叫最后一次):
文件“”,第1行,是否在中?
NameError:未定义名称“函数”
我之所以选择它是因为
>>> type(x)
<type 'function'>
>类型(x)
以下内容应返回布尔值:
callable(x)
尝试使用
callable(x)
如果这是针对Python2.x或Python3.2+,您可以使用。它曾经被弃用,但现在还没有被预先确定,所以您可以再次使用它。您可以在此处阅读讨论:。您可以通过以下方式执行此操作:
callable(obj)
hasattr(obj, '__call__')
如果这是针对Python3.x但在3.2之前的版本,请检查对象是否具有\uuuu call\uuu
属性。您可以通过以下方式执行此操作:
callable(obj)
hasattr(obj, '__call__')
经常建议的or方法(两者都有)附带了一些警告。对于非Python函数,它返回False
。例如,大多数是用C语言实现的,而不是用Python实现的,因此它们返回False
:
>>> isinstance(open, types.FunctionType)
False
>>> callable(open)
True
因此
types.FunctionType
可能会给您带来令人惊讶的结果。检查duck类型对象属性的正确方法是询问它们是否会嘎嘎作响,而不是查看它们是否适合duck大小的容器。内置命名空间中没有构造函数的内置类型(例如函数、生成器、方法)位于类型模块中。您可以在isinstance
调用中使用types.FunctionType
:
>>> import types
>>> types.FunctionType
<class 'function'>
>>> def f(): pass
>>> isinstance(f, types.FunctionType)
True
>>> isinstance(lambda x : None, types.FunctionType)
True
打开
(内置函数有不同的类型):
如果您正在执行一些特定于类型.FunctionType
实例的操作,如反编译字节码或检查闭包变量,请使用类型.FunctionType
,但如果您只需要一个对象像函数一样可调用,请使用可调用可调用(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,“\uu call”
,或者试试
test_as_func = True
try:
b()
except TypeError:
test_as_func = False
except:
pass
当然,这不会告诉您它是否可调用,而是在执行时抛出一个TypeError
,或者一开始就不可调用。这对您可能无关紧要。函数只是一个带有\uuu调用\uuu
方法的类,所以您可以这样做
hasattr(obj, '__call__')
例如:
>>> hasattr(x, '__call__')
True
>>> x = 2
>>> hasattr(x, '__call__')
False
>>> def x():
... raise TypeError
...
>>> hasattr(x, '__call__')
True # Correct
>>> try:
... x()
... except TypeError:
... print "x was not callable"
...
x was not callable # Wrong!
这是“最好”的方法,但根据您需要知道它是可调用的还是note的原因,您可以将它放在try/execpt块中:
try:
x()
except TypeError:
print "was not callable"
如果try/except比hasattr(x,“\uuu call\uuuu”):x()
更像Python'y,这是有争议的。。我想说hasattr
更准确,因为您不会意外发现错误的类型错误,例如:
>>> hasattr(x, '__call__')
True
>>> x = 2
>>> hasattr(x, '__call__')
False
>>> def x():
... raise TypeError
...
>>> hasattr(x, '__call__')
True # Correct
>>> try:
... x()
... except TypeError:
... print "x was not callable"
...
x was not callable # Wrong!
Python的2to3工具()建议:
import collections
isinstance(obj, collections.Callable)
似乎选择了这个方法而不是hasattr(x,“\uu调用”方法是因为。在Python3中,我提出了
type(f)==type(lambda x:x)
,如果f
是一个函数,则产生True
,如果不是,则产生False
。但是我想我更喜欢isinstance(f,types.FunctionType)
,它感觉不那么特别。我想做类型(f)是函数
,但那不起作用 您可以从模块导入isfunction
如果您想检测语法上看起来像函数的所有东西:函数、方法、内置的fun/meth、lambda。。。但是排除可调用对象(定义了
\uuuu调用\uuu
方法的对象),然后尝试以下方法:
import types
isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType))
我将其与
is*()
checks ininspect
模块的代码进行了比较,上面的表达式更加完整,尤其是当您的目标是过滤掉任何函数或检测对象的常规属性时。在前面的回答之后,我得出了以下结论:
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)
任何函数都是一个类,因此您可以使用实例x的类的名称并比较:
if(x.__class__.__name__ == 'function'):
print "it's a function"
您可以检查用户定义的函数是否具有属性
函数名
,函数文档
等,而不是检查调用
(这不是函数独有的)。这对方法不起作用
>>> def x(): pass
...
>>> hasattr(x, 'func_name')
True
另一种检查方法是使用inspect
模块中的isfunction()
方法
>>> import inspect
>>> inspect.isfunction(x)
True
要检查对象是否是方法,请使用
inspect.ismethod()
接受的答案在提供时被认为是正确的。因为它
事实证明,Python中的callable()
是无法替代的
3.2:具体地说,callable()
检查被调用对象的tp\u 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
我们可以通过从
班级。为了让事情更加精彩,在实例中添加一个假的调用
>>> 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
是错误的:
can\u o\u spam
毕竟有这个属性;只是打电话的时候没用
实例
更微妙的是,isinstance()
也会出错:
>>> isinstance(can_o_spam, collections.Callable)
True
因为我们之前使用了此检查,后来删除了该方法,abc.ABCMeta
缓存结果。可以说这是abc.ABCMeta中的一个bug。也就是说,
真的没有比这更精确的方法了
由于typeobject->tp\u调用
插槽方法在任何其他w中都不可访问
>>> isinstance(can_o_spam, collections.Callable)
True
def myfunc(x):
try:
x()
except TypeError:
raise Exception("Not callable")
>>> import collections
>>> Test = collections.namedtuple('Test', [])
>>> callable(Test)
True
>>> hasattr(Test, '__call__')
True
>>> import inspect
>>> inspect.isfunction(Test)
False
>>> def t(): pass
>>> inspect.isfunction(t)
True
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!
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
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)
#!/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]
"""
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>
"""
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
def a():pass
type(a) #<class 'function'>
str(type(a))=="<class 'function'>" #True
b = lambda x:x*2
str(type(b))=="<class 'function'>" #True
#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
In [50]: isinstance(getattr, types.BuiltinFunctionType)
Out[50]: True
In [51]: isinstance(detect_function, types.BuiltinFunctionType)
Out[51]: False
str(type(a))=="<class 'function'>"
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]
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')