16

In Python I need to efficiently and generically test whether an attribute of a class is an instance method. The inputs to the call would be the name of the attribute being checked (a string) and an object.

hasattr returns true regardless of whether the attribute is an instance method or not.

Any suggestions?


For example:

class Test(object):
    testdata = 123

    def testmethod(self):
        pass

test = Test()
print ismethod(test, 'testdata') # Should return false
print ismethod(test, 'testmethod') # Should return true
Richard Dorman
  • 23,170
  • 16
  • 45
  • 49
  • 2
    Are you sure you need to know it it's a method? Aren't you really itching to know if you can call it? Those are not necessarily the same thing (although of course they often are). – Lennart Regebro Jul 07 '09 at 09:40
  • What's wrong with reading the source? This is Python -- you have the source -- why can't you simply read it? – S.Lott Jul 07 '09 at 11:31
  • 3
    Reading the source isn't any help - presumably he's writing some code that needs to know the answer at runtime. Possibly iterating through all attrs on an object, for instance. – Jonathan Hartley May 24 '10 at 16:03

5 Answers5

21
def hasmethod(obj, name):
    return hasattr(obj, name) and type(getattr(obj, name)) == types.MethodType
Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
  • 9
    Be aware that "getattr" may involve code execution. This answer is getting the value of obj's "name" attribute, and then testing the type of that value. If using Python 3, import inspect, and replace "getattr" with "inspect.getattr_static", which avoids that evaluation. http://docs.python.org/3.3/library/inspect.html#fetching-attributes-statically – ToolmakerSteve Nov 25 '13 at 20:54
  • this only works if you simply want to check if the method is an instance method, It fails to identify whether the method is binding to the current instance. – Sajuuk May 10 '19 at 06:41
8

You can use the inspect module:

class A(object):
    def method_name(self):
        pass


import inspect

print inspect.ismethod(getattr(A, 'method_name')) # prints True
a = A()
print inspect.ismethod(getattr(a, 'method_name')) # prints True
Steef
  • 33,059
  • 4
  • 45
  • 36
  • The question asks for a function which would return `False` for your example capital `A` and true for your example lowercase 'a' That is, the question was, from an object attribute, how can we tell whether it is callable AND that it is attribute of the instance, **not** a class attribute (a static member function). – Toothpick Anemone Mar 12 '18 at 02:41
7
import types

print isinstance(getattr(your_object, "your_attribute"), types.MethodType)
mthurlin
  • 26,247
  • 4
  • 39
  • 46
5

This function checks if the attribute exists and then checks if the attribute is a method using the inspect module.

import inspect

def ismethod(obj, name):
    if hasattr(obj, name):
        if inspect.ismethod(getattr(obj, name)):
            return True
    return False

class Foo:
    x = 0
    def bar(self):
        pass

foo = Foo()
print ismethod(foo, "spam")
print ismethod(foo, "x")
print ismethod(foo, "bar")
Otto Allmendinger
  • 27,448
  • 7
  • 68
  • 79
1

Be aware that @classmethod-decorated functions will pass all the tests in other answers. Do you want these to be considered 'instance methods'? Maybe it's just semantics, but they by definition operate on the class, not the spawned instance. I am not sure about the cases where hasmethod2 (my proposed solution) fails, but at least it can be wary of class methods:


import inspect
import types

def hasmethod(obj, name):
    return hasattr(obj, name) and type(getattr(obj, name)) == types.MethodType

def hasmethod2(obj, name):
    try:
        attr = getattr(obj, name)
        return not inspect.isclass(attr.__self__)
    except AttributeError:
        return False

class Test(object):
    testdata = 123

    def testmethod(self):
        pass

    @classmethod
    def testmethod2(cls):
        pass

# Returns True. This may be undesired depending on your definition of 'instance method'
hasmethod(Test(), 'testmethod2')
 
# Returns False
hasmethod2(Test(), 'testmethod2')

It works because __self__ is bound to the primary calling argument (class instance for classmethod, object instance for normal attributes, module or nothing for various built-ins). Thus, checking for the existence of __self__ and that __self__ is not a class rules out non-function attributes and classmethods, respectively.

ntjess
  • 570
  • 6
  • 10