9

I have a function in Python which is iterating over the attributes returned from dir(obj), and I want to check to see if any of the objects contained within is a function, method, built-in function, etc. Normally you could use callable() for this, but I don't want to include classes. The best I've come up with so far is:

isinstance(obj, (types.BuiltinFunctionType, types.FunctionType, types.MethodType))

Is there a more future-proof way to do this check?

Edit: I misspoke before when I said: "Normally you could use callable() for this, but I don't want to disqualify classes." I actually do want to disqualify classes. I want to match only functions, not classes.

4 Answers 4

17

The inspect module has exactly what you want:

inspect.isroutine( obj )

FYI, the code is:

def isroutine(object):
    """Return true if the object is any kind of function or method."""
    return (isbuiltin(object)
            or isfunction(object)
            or ismethod(object)
            or ismethoddescriptor(object))
Sign up to request clarification or add additional context in comments.

1 Comment

isroutine() returns False for partials. hasattr(obj, 'call') returns True for partials.
5

If you want to exclude classes and other random objects that may have a __call__ method, and only check for functions and methods, these three functions in the inspect module

inspect.isfunction(obj)
inspect.isbuiltin(obj)
inspect.ismethod(obj)

should do what you want in a future-proof way.

2 Comments

Upvoted, prefer over hasattr solution because you can define a call item in a user-defined class and hasattr will happily tell you that class has the call attribute, even if it isn't a function.
I don't see how this is better than the solution in my original comment? You still have to check for all three explicitly.
3
if hasattr(obj, '__call__'): pass

This also fits in better with Python's "duck typing" philosophy, because you don't really care what it is, so long as you can call it.

It's worth noting that callable() is being removed from Python and is not present in 3.0.

1 Comment

Worth noting that this will only work for new-style classes. You get False for old-style classes.
1

Depending on what you mean by 'class':

callable( obj ) and not inspect.isclass( obj )

or:

callable( obj ) and not isinstance( obj, types.ClassType )

For example, results are different for 'dict':

>>> callable( dict ) and not inspect.isclass( dict )
False
>>> callable( dict ) and not isinstance( dict, types.ClassType )
True

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.