我有一个变量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'>
当前回答
尝试使用callable(x)。
摘录:
如果对象参数显示为可调用,则返回True,否则返回False。
其他回答
在Python3中,我提出了type (f) == type (lambda x:x),如果f是一个函数,则输出True,如果不是则输出False。但我想我更喜欢isinstance (f, types.FunctionType),它感觉不那么特别。我想写type (f) is function,但这行不通。
如果传递的对象可以在Python中调用,callable(x)将返回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)
你将得到<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
当然,这不会告诉您它是可调用的,但在执行时抛出TypeError,还是一开始就不可调用。这对你来说可能无关紧要。
结果
callable(x) | hasattr(x, '__call__') | inspect.isfunction(x) | inspect.ismethod(x) | inspect.isgeneratorfunction(x) | inspect.iscoroutinefunction(x) | inspect.isasyncgenfunction(x) | isinstance(x, typing.Callable) | isinstance(x, types.BuiltinFunctionType) | isinstance(x, types.BuiltinMethodType) | isinstance(x, types.FunctionType) | isinstance(x, types.MethodType) | isinstance(x, types.LambdaType) | isinstance(x, functools.partial) | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
√ | √ | × | × | × | × | × | √ | √ | √ | × | × | × | × | |
func | √ | √ | √ | × | × | × | × | √ | × | × | √ | × | √ | × |
functools.partial | √ | √ | × | × | × | × | × | √ | × | × | × | × | × | √ |
<lambda> | √ | √ | √ | × | × | × | × | √ | × | × | √ | × | √ | × |
generator | √ | √ | √ | × | √ | × | × | √ | × | × | √ | × | √ | × |
async_func | √ | √ | √ | × | × | √ | × | √ | × | × | √ | × | √ | × |
async_generator | √ | √ | √ | × | × | × | √ | √ | × | × | √ | × | √ | × |
A | √ | √ | × | × | × | × | × | √ | × | × | × | × | × | × |
meth | √ | √ | √ | × | × | × | × | √ | × | × | √ | × | √ | × |
classmeth | √ | √ | × | √ | × | × | × | √ | × | × | × | √ | × | × |
staticmeth | √ | √ | √ | × | × | × | × | √ | × | × | √ | × | √ | × |
import types
import inspect
import functools
import typing
def judge(x):
name = x.__name__ if hasattr(x, '__name__') else 'functools.partial'
print(name)
print('\ttype({})={}'.format(name, type(x)))
print('\tcallable({})={}'.format(name, callable(x)))
print('\thasattr({}, \'__call__\')={}'.format(name, hasattr(x, '__call__')))
print()
print('\tinspect.isfunction({})={}'.format(name, inspect.isfunction(x)))
print('\tinspect.ismethod({})={}'.format(name, inspect.ismethod(x)))
print('\tinspect.isgeneratorfunction({})={}'.format(name, inspect.isgeneratorfunction(x)))
print('\tinspect.iscoroutinefunction({})={}'.format(name, inspect.iscoroutinefunction(x)))
print('\tinspect.isasyncgenfunction({})={}'.format(name, inspect.isasyncgenfunction(x)))
print()
print('\tisinstance({}, typing.Callable)={}'.format(name, isinstance(x, typing.Callable)))
print('\tisinstance({}, types.BuiltinFunctionType)={}'.format(name, isinstance(x, types.BuiltinFunctionType)))
print('\tisinstance({}, types.BuiltinMethodType)={}'.format(name, isinstance(x, types.BuiltinMethodType)))
print('\tisinstance({}, types.FunctionType)={}'.format(name, isinstance(x, types.FunctionType)))
print('\tisinstance({}, types.MethodType)={}'.format(name, isinstance(x, types.MethodType)))
print('\tisinstance({}, types.LambdaType)={}'.format(name, isinstance(x, types.LambdaType)))
print('\tisinstance({}, functools.partial)={}'.format(name, isinstance(x, functools.partial)))
def func(a, b):
pass
partial = functools.partial(func, a=1)
_lambda = lambda _: _
def generator():
yield 1
yield 2
async def async_func():
pass
async def async_generator():
yield 1
class A:
def __call__(self, a, b):
pass
def meth(self, a, b):
pass
@classmethod
def classmeth(cls, a, b):
pass
@staticmethod
def staticmeth(a, b):
pass
for func in [print,
func,
partial,
_lambda,
generator,
async_func,
async_generator,
A,
A.meth,
A.classmeth,
A.staticmeth]:
judge(func)
Time
选择三种最常见的方法:
可调用的(x) hasattr (x, __call__) isinstance (x, typing.Callable)
time/s | |
---|---|
callable(x) | 0.86 |
hasattr(x, '__call__') | 1.36 |
isinstance(x, typing.Callable) | 12.19 |
import typing
from timeit import timeit
def x():
pass
def f1():
return callable(x)
def f2():
return hasattr(x, '__call__')
def f3():
return isinstance(x, typing.Callable)
print(timeit(f1, number=10000000))
print(timeit(f2, number=10000000))
print(timeit(f3, number=10000000))
# 0.8643081
# 1.3563508
# 12.193492500000001
在一些答案中提到的使用hasattr(obj, '__call__')和callable(.)的解决方案有一个主要缺点:对于具有__call__()方法的类和类的实例,它们都返回True。如。
>>> import collections
>>> Test = collections.namedtuple('Test', [])
>>> callable(Test)
True
>>> hasattr(Test, '__call__')
True
检查一个对象是否是用户定义的函数(只有a that)的一个正确方法是使用isfunction(.):
>>> import inspect
>>> inspect.isfunction(Test)
False
>>> def t(): pass
>>> inspect.isfunction(t)
True
如果您需要检查其他类型,请查看inspect -检查活动对象。
任何函数都是一个类,所以你可以取实例x的类名并比较:
if(x.__class__.__name__ == 'function'):
print "it's a function"