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

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

我曾希望我可以做些类似的事情:

>>> isinstance(x, function)

但这给了我:

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

我之所以选择,是因为

>>> type(x)
<type 'function'>

I have a variable, x, and I want to know whether it is pointing to a function or not.

I had hoped I could do something like:

>>> isinstance(x, function)

But that gives me:

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

The reason I picked that is because

>>> type(x)
<type 'function'>

回答 0

如果这是用于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除非您对功能是什么有一个非常具体的了解,否则不要使用。

If this is for Python 2.x or for Python 3.2+, you can also use callable(). It used to be deprecated, but is now undeprecated, so you can use it again. You can read the discussion here: http://bugs.python.org/issue10518. You can do this with:

callable(obj)

If this is for Python 3.x but before 3.2, check if the object has a __call__ attribute. You can do this with:

hasattr(obj, '__call__')

The oft-suggested types.FunctionTypes approach is not correct because it fails to cover many cases that you would presumably want it to pass, like with builtins:

>>> isinstance(open, types.FunctionType)
False

>>> callable(open)
True

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. Don’t use types.FunctionType unless you have a very specific idea of what a function is.


回答 1

内置命名空间中没有构造函数的内置类型(例如,函数,生成器,方法)位于types模块中。您可以types.FunctionTypeisinstance通话中使用:

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

请注意,这使用了非常特殊的“功能”概念,通常不是您所需要的。例如,它拒绝zip(从技术上讲是一个类):

>>> type(zip), isinstance(zip, types.FunctionType)
(<class 'type'>, False)

open (内置函数的类型不同):

>>> type(open), isinstance(open, types.FunctionType)
(<class 'builtin_function_or_method'>, False)

random.shuffle(从技术上讲是一个隐藏random.Random实例的方法):

>>> type(random.shuffle), isinstance(random.shuffle, types.FunctionType)
(<class 'method'>, False)

如果您要针对types.FunctionType实例执行特定操作,例如反编译其字节码或检查闭包变量,请使用types.FunctionType,但如果您只需要像函数一样可调用的对象,请使用callable

Builtin types that don’t have constructors in the built-in namespace (e.g. functions, generators, methods) are in the types module. You can use types.FunctionType in an isinstance call:

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

Note that this uses a very specific notion of “function” that is usually not what you need. For example, it rejects zip (technically a class):

>>> type(zip), isinstance(zip, types.FunctionType)
(<class 'type'>, False)

open (built-in functions have a different type):

>>> type(open), isinstance(open, types.FunctionType)
(<class 'builtin_function_or_method'>, False)

and random.shuffle (technically a method of a hidden random.Random instance):

>>> type(random.shuffle), isinstance(random.shuffle, types.FunctionType)
(<class 'method'>, False)

If you’re doing something specific to types.FunctionType instances, like decompiling their bytecode or inspecting closure variables, use types.FunctionType, but if you just need an object to be callable like a function, use callable.


回答 2

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

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

Since Python 2.1 you can import isfunction from the inspect module.

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

回答 3

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

The accepted answer was at the time it was offered thought to be correct. As it turns out, there is no substitute for callable(), which is back in Python 3.2: Specifically, callable() checks the tp_call field of the object being tested. There is no plain Python equivalent. Most of the suggested tests are correct most of the time:

>>> 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

We can throw a monkey-wrench into this by removing the __call__ from the class. And just to keep things extra exciting, add a fake __call__ to the instance!

>>> del Spam.__call__
>>> can_o_spam.__call__ = lambda *args: 'OK?'

Notice this really isn’t callable:

>>> can_o_spam()
Traceback (most recent call last):
  ...
TypeError: 'Spam' object is not callable

callable() returns the correct result:

>>> callable(can_o_spam)
False

But hasattr is wrong:

>>> hasattr(can_o_spam, '__call__')
True

can_o_spam does have that attribute after all; it’s just not used when calling the instance.

Even more subtle, isinstance() also gets this wrong:

>>> isinstance(can_o_spam, collections.Callable)
True

Because we used this check earlier and later deleted the method, abc.ABCMeta caches the result. Arguably this is a bug in abc.ABCMeta. That said, there’s really no possible way it could produce a more accurate result than the result than by using callable() itself, since the typeobject->tp_call slot method is not accessible in any other way.

Just use callable()


回答 4

以下应返回布尔值:

callable(x)

The following should return a boolean:

callable(x)

回答 5

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

import collections
isinstance(obj, collections.Callable)

似乎是hasattr(x, '__call__')因为http://bugs.python.org/issue7006选择了它而不是方法。

Python’s 2to3 tool (http://docs.python.org/dev/library/2to3.html) suggests:

import collections
isinstance(obj, collections.Callable)

It seems this was chosen instead of the hasattr(x, '__call__') method because of http://bugs.python.org/issue7006.


回答 6

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)

您将获得<class 'A'> True<type function> True作为输出。

isinstance可以很好地确定某物是否是一个函数(try isinstance(b, types.FunctionType));如果您真的想知道是否可以调用某些东西,可以使用hasattr(b, '__call__')也可以尝试一下。

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

当然,这不会告诉您它是否可以调用,但是TypeError在执行时会引发一个,还是一开始就不可调用。这可能对您来说并不重要。

callable(x) will return true if the object passed can be called in Python, but the function does not exist in Python 3.0, and properly speaking will not distinguish between:

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)

You’ll get <class 'A'> True and <type function> True as output.

isinstance works perfectly well to determine if something is a function (try isinstance(b, types.FunctionType)); if you’re really interested in knowing if something can be called, you can either use hasattr(b, '__call__') or just try it.

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

This, of course, won’t tell you whether it’s callable but throws a TypeError when it executes, or isn’t callable in the first place. That may not matter to you.


回答 7

如果要检测语法上看起来像函数的所有内容:函数,方法,内置fun / meth,lambda …,但要排除可调用对象(__call__定义了方法的对象),请尝试以下方法:

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

我将其与模块中的is*()检查代码进行了比较,inspect并且上面的表达式更加完整,尤其是当您的目标是过滤掉任何功能或检测对象的常规属性时。

If you want to detect everything that syntactically looks like a function: a function, method, built-in fun/meth, lambda … but exclude callable objects (objects with __call__ method defined), then try this one:

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

I compared this with the code of is*() checks in inspect module and the expression above is much more complete, especially if your goal is filtering out any functions or detecting regular properties of an object.


回答 8

尝试使用callable(x)

Try using callable(x).


回答 9

如果您已学习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] <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

If you have learned C++, you must be familiar with function object or functor, means any object that can be called as if it is a function.

In C++, an ordinary function is a function object, and so is a function pointer; more generally, so is an object of a class that defines operator(). In C++11 and greater, the lambda expression is the functor too.

Similarity, in Python, those functors are all callable. An ordinary function can be callable, a lambda expression can be callable, a functional.partial can be callable, the instances of class with a __call__() method can be callable.


Ok, go back to question : I have a variable, x, and I want to know whether it is pointing to a function or not.

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 the xtypes.XXX suggested by @Ryan is a better choice.

Then I do an experiment using those code:

#!/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.

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.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:

## 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.

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.

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>
"""

I draw a table of callable functor’s types using the data.

enter image description here

Then you can choose the functors’ types that suitable.

such as:

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

回答 10

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

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

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

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

As the accepted answer, John Feminella stated that:

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.

Even though, there’re two libs to distinguish functions strictly, I draw an exhaustive comparable table:

8.9. types — Dynamic type creation and names for built-in types — Python 3.7.0 documentation

30.13. inspect — Inspect live objects — Python 3.7.0 documentation

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

The “duck typing” is a preferred solution for general purpose:

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

As for the builtins function

In [43]: callable(hasattr)
Out[43]: True

When go one more step to check if builtin function or user-defined funtion

#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

Determine if builtin function

In [50]: isinstance(getattr, types.BuiltinFunctionType)
Out[50]: True
In [51]: isinstance(detect_function, types.BuiltinFunctionType)
Out[51]: False

Summary

Employ callable to duck type checking a function,
Use types.BuiltinFunctionType if you have further specified demand.


回答 11

函数只是带有__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!

A function is just a class with a __call__ method, so you can do

hasattr(obj, '__call__')

For example:

>>> hasattr(x, '__call__')
True

>>> x = 2
>>> hasattr(x, '__call__')
False

That is the “best” way of doing it, but depending on why you need to know if it’s callable or note, you could just put it in a try/execpt block:

try:
    x()
except TypeError:
    print "was not callable"

It’s arguable if try/except is more Python’y than doing if hasattr(x, '__call__'): x().. I would say hasattr is more accurate, since you wont accidently catch the wrong TypeError, for example:

>>> def x():
...     raise TypeError
... 
>>> hasattr(x, '__call__')
True # Correct
>>> try:
...     x()
... except TypeError:
...     print "x was not callable"
... 
x was not callable # Wrong!

回答 12

这是另外两种方式:

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!

Here’s a couple of other ways:

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

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

Here’s how I came up with the second:

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

回答 13

'__call__'您可以检查用户定义的函数是否具有属性,等等func_name,而不是进行检查(这不是函数所独有的)func_doc。这不适用于方法。

>>> def x(): pass
... 
>>> hasattr(x, 'func_name')
True

另一种检查isfunction()方法是使用inspect模块中的方法。

>>> import inspect
>>> inspect.isfunction(x)
True

要检查对象是否为方法,请使用 inspect.ismethod()

Instead of checking for '__call__' (which is not exclusive to functions), you can check whether a user-defined function has attributes func_name, func_doc, etc. This does not work for methods.

>>> def x(): pass
... 
>>> hasattr(x, 'func_name')
True

Another way of checking is using the isfunction() method from the inspect module.

>>> import inspect
>>> inspect.isfunction(x)
True

To check if an object is a method, use inspect.ismethod()


回答 14

由于类也具有__call__方法,因此我建议另一个解决方案:

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

Since classes also have __call__ method, I recommend another solution:

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

回答 15

请注意,Python类也是可调用的。

要获取功能(按功能,我们指的是标准功能和lambda),请使用:

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)

Note that Python classes are also callable.

To get functions (and by functions we mean standard functions and lambdas) use:

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)

回答 16

无论函数是一个类,因此您都可以使用实例x的类的名称并进行比较:


if(x.__class__.__name__ == 'function'):
     print "it's a function"

Whatever function is a class so you can take the name of the class of instance x and compare:


if(x.__class__.__name__ == 'function'):
     print "it's a function"

回答 17

在某些答案中使用hasattr(obj, '__call__')callable(.)提到的解决方案有一个主要缺点:都返回True类和带有__call__()方法的类实例。例如。

>>> import collections
>>> Test = collections.namedtuple('Test', [])
>>> callable(Test)
True
>>> hasattr(Test, '__call__')
True

检查对象是否是用户定义的函数(除了那个以外的任何东西)的一种正确方法是使用isfunction(.)

>>> import inspect
>>> inspect.isfunction(Test)
False
>>> def t(): pass
>>> inspect.isfunction(t)
True

如果需要检查其他类型,请查看一下检查—检查活动对象

The solutions using hasattr(obj, '__call__') and callable(.) mentioned in some of the answers have a main drawback: both also return True for classes and instances of classes with a __call__() method. Eg.

>>> import collections
>>> Test = collections.namedtuple('Test', [])
>>> callable(Test)
True
>>> hasattr(Test, '__call__')
True

One proper way of checking if an object is a user-defined function (and nothing but a that) is to use isfunction(.):

>>> import inspect
>>> inspect.isfunction(Test)
False
>>> def t(): pass
>>> inspect.isfunction(t)
True

If you need to check for other types, have a look at inspect — Inspect live objects.


回答 18

精确功能检查器

callable是一个非常好的解决方案。但是,我想以相反的方式对待约翰·费米内拉。而不是像这样说:

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

我们将这样处理:

检查某物是否是鸭子的正确方法不是通过若干过滤器查看它是否会发出嘎嘎声,而是通过多种过滤器查看它是否真的是鸭子,而不是仅仅从表面上检查它是否看起来像鸭子。

我们将如何实施

‘types’模块具有大量用于检测功能的类,其中最有用的是type.FunctionType,但是还有很多其他类,例如方法类型,内置类型和lambda类型。我们还将“ functools.partial”对象视为函数。

我们检查所有类型是否简单的简单方法是使用isinstance条件。以前,我想创建一个继承自上述所有类的基类,但我无法做到这一点,因为Python不允许我们继承上述某些类。

下表列出了哪些类别可以对哪些功能进行分类:

功能表from kinght-金 以上功能表由kinght-金

起作用的代码

现在,这是完成我们上面描述的所有工作的代码。

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]

一个错误是is_function(partial),因为它是一个类,而不是一个函数,而这恰好是函数,而不是类。这是预览版,可让您试用其中的代码。

结论

如果希望通过对绝对值的鸭式输入来检查,callable(obj)是检查对象是否为函数的首选方法

我们的自定义is_function(obj),如果您不将可调用类实例算作一个函数,而是仅定义为内置函数或使用lambdadef,则可能需要进行一些编辑才能检查对象是否为函数的首选方法或部分

而且我认为这一切都包含在内。祝你有美好的一天!

An Exact Function Checker

callable is a very good solution. However, I wanted to treat this the opposite way of John Feminella. Instead of treating it like this saying:

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.

We’ll treat it like this:

The proper way to check if something is a duck is not to see if it can quack, but rather to see if it truly is a duck through several filters, instead of just checking if it seems like a duck from the surface.

How Would We Implement It

The ‘types’ module has plenty of classes to detect functions, the most useful being types.FunctionType, but there are also plenty of others, like a method type, a built in type, and a lambda type. We also will consider a ‘functools.partial’ object as being a function.

The simple way we check if it is a function is by using an isinstance condition on all of these types. Previously, I wanted to make a base class which inherits from all of the above, but I am unable to do that, as Python does not allow us to inherit from some of the above classes.

Here’s a table of what classes can classify what functions:

Functions table from kinght-金 Above function table by kinght-金

The Code Which Does It

Now, this is the code which does all of the work we described from above.

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]

The one false was is_function(partial), because that’s a class, not a function, and this is exactly functions, not classes. Here is a preview for you to try out the code from.

Conclusion

callable(obj) is the preferred method to check if an object is a function if you want to go by duck-typing over absolutes.

Our custom is_function(obj), maybe with some edits is the preferred method to check if an object is a function if you don’t any count callable class instance as a function, but only functions defined built-in, or with lambda, def, or partial.

And I think that wraps it all up. Have a good day!


回答 19

在Python3中,我想出了type (f) == type (lambda x:x)产生Trueif f是否为函数的结果False。但是我想我更喜欢isinstance (f, types.FunctionType),感觉不太特别。我想做type (f) is function,但这不起作用。

In Python3 I came up with type (f) == type (lambda x:x) which yields True if f is a function and False if it is not. But I think I prefer isinstance (f, types.FunctionType), which feels less ad hoc. I wanted to do type (f) is function, but that doesn’t work.


回答 20

在先前的答复之后,我想到了这一点:

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)

Following previous replies, I came up with this:

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)

回答 21

您可以尝试以下方法:

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')

You could try this:

if obj.__class__.__name__ in ['function', 'builtin_function_or_method']:
    print('probably a function')

or even something more bizarre:

if "function" in lower(obj.__class__.__name__):
    print('probably a function')

回答 22

如果该值可调用,代码将继续执行调用,则只需执行调用并catch即可TypeError

def myfunc(x):
  try:
    x()
  except TypeError:
    raise Exception("Not callable")

If the code will go on to perform the call if the value is callable, just perform the call and catch TypeError.

def myfunc(x):
  try:
    x()
  except TypeError:
    raise Exception("Not callable")

回答 23

以下是检查它的“替代方法”。它也适用于lambda。

def a():pass
type(a) #<class 'function'>
str(type(a))=="<class 'function'>" #True

b = lambda x:x*2
str(type(b))=="<class 'function'>" #True

The following is a “repr way” to check it. Also it works with lambda.

def a():pass
type(a) #<class 'function'>
str(type(a))=="<class 'function'>" #True

b = lambda x:x*2
str(type(b))=="<class 'function'>" #True

回答 24

这对我有用:

str(type(a))=="<class 'function'>"

This works for me:

str(type(a))=="<class 'function'>"

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。