tags:

views:

1521

answers:

6

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'>
+3  A: 

The following should return a boolean:

callable(x)
Nikhil Chelliah
That solves his problem, but he's still created a mystery: if x is of class 'function' in module __builtin__, and help(x.__class__) describes "class function", why is "function" apparently "not defined"?
Ken
"function" isn't a keyword or a built-in type. The type of functions is defined in the "types" module, as "types.FunctionType"
Chris B.
+1  A: 

Try using callable(x).

maxyfc
+21  A: 

Just check if the object has a __call__ attribute. Don't use callable(), as this is being deprecated. You can check this with:

hasattr(obj, '__call__')
John Feminella
ref: http://docs.python.org/3.0/whatsnew/3.0.html#builtins
John Fouhy
This also won't tell you if it's a function--just if it can be called.
Chris B.
Arguably, you shouldn't care about that distinction..
John Fouhy
Depends on the application whether the distinction matters or not; I suspect you're right that it doesn't for the original question, but that's far from certain.
Chris B.
+17  A: 

Builtin types that don't have constructors (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
Ryan
+1 answering the question. However, trying to guess whether an object is a function — or even if it is any callable object — is usually a mistake. Without further information from the OP it's difficult to dismiss it out of hand of course, but still...
bobince
+4  A: 

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.

Chris B.
+3  A: 

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!
dbr
Use exception handling to protect against unexpected behavior only, never for logic flow--that is definitely not Pythonic.
gotgenes
Well, hasattr basically does a getattr in a try/except block (albeit in C). http://blog.jancewicz.net/2007/10/reflection-hasattr.html
dbr
@dbr: But hasattr is more aesthetic.
Nikhil Chelliah