我有一个变量x,我想知道它是否指向一个函数。
我希望我能做一些像这样的事情:
>>> isinstance(x, function)
但这给了我:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'function' is not defined
我选这个是因为
>>> type(x)
<type 'function'>
我有一个变量x,我想知道它是否指向一个函数。
我希望我能做一些像这样的事情:
>>> isinstance(x, function)
但这给了我:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'function' is not defined
我选这个是因为
>>> type(x)
<type 'function'>
当前回答
如果你学过c++,你一定熟悉函数对象或函子,这意味着任何可以像函数一样调用的对象。
在c++中,普通函数是函数对象,函数指针也是;更一般地说,定义operator()的类的对象也是。在c++ 11及以上版本中,lambda表达式也是函子。
相似的是,在Python中,这些函子都是可调用的。一个普通的函数可以被调用,一个lambda表达式可以被调用,一个函数。Partial可以被调用,具有__call__()方法的类的实例可以被调用。
好,回到问题:我有一个变量x,我想知道它是否指向一个函数。
如果你想判断对象是否像一个函数,那么@John Feminella建议的callable方法是可以的。 如果您想判断一个对象是否只是一个普通函数(不是一个可调用的类实例或lambda表达式),那么xtypes。@Ryan建议的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>
"""
我用这些数据绘制了一个可调用函子类型的表。
然后你可以选择合适的函子类型。
如:
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
其他回答
如果你想检测所有语法上看起来像函数的东西:函数、方法、内置的fun/meth、lambda…但排除可调用对象(定义了__call__方法的对象),然后尝试这个:
import types
isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType))
我将其与inspect模块中的is*()检查代码进行了比较,上面的表达式要完整得多,特别是如果您的目标是过滤任何函数或检测对象的常规属性。
函数只是一个带有__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比doing if hasattr(x, '__call__'): x()更适合Python,这是有争议的。我会说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!
这是我的代码:
# -*- coding: utf-8 -*-
import hashlib
import inspect
# calc everything to md5!!
def count_md5(content):
if isinstance(content, dict):
return count_md5(
[(str(k), count_md5(content[k])) for k in sorted(content.keys())],
)
elif isinstance(content, (list, tuple)):
content = [count_md5(k) for k in content]
elif callable(content):
return make_callable_hash(content)
return calc_md5(str(content))
def calc_md5(content):
m2 = hashlib.md5()
if isinstance(content, str):
m2.update(content.encode("utf8"))
else:
m2.update(content)
return m2.hexdigest()
def make_callable_hash(content):
if inspect.isclass(content):
h = []
for attr in [i for i in sorted(dir(content)) if not i.startswith("__")]:
v = getattr(content, attr)
h.append(count_md5(v))
return calc_md5("".join(h))
return calc_md5(content.__name__)
对于callable,大多数时候我们只是想看看属性的值是否一致,所以我们可以取callable的所有属性并计算它。 如果它是一个类'callable'将返回true,所以它不是很严格
尝试使用callable(x)。
摘录:
如果对象参数显示为可调用,则返回True,否则返回False。
根据之前的回复,我想出了这个:
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)