How do I detect whether a Python variable is a 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'>
If this is for Python 2.x or for Python 3.2+, you can 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
or inspect.isfunction
approach (both do the exact same thing) comes with a number of caveats. It returns False
for non-Python functions. Most builtin functions, for example, are implemented in C and not Python, so they return False
:
>>> isinstance(open, types.FunctionType)
False
>>> callable(open)
True
so types.FunctionType
might give you surprising results. 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.
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:
>>> import types
>>> types.FunctionType
<class 'function'>
>>> def f(): pass
>>> isinstance(f, types.FunctionType)
True
>>> isinstance(lambda x : None, types.FunctionType)
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
.
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