This is a simplified example of my actual problem.
I have a class foo defined like this in foo.py:
class foo(object):
def __init__(self):
pass
def bar(self):
return True
@property
def baz(self):
return False
Now, I want to use the inspect module to get the methods of the foo class (including baz). This is what I have so far in getmethods.py:
import foo
import inspect
classes = inspect.getmembers(foo, inspect.isclass)
for cls in classes:
methods = inspect.getmembers(cls[1], inspect.ismethod)
print methods
When I run this script, I get the following output (which isn't exactly unexpected):
[('__init__', <unbound method foo.__init__>), ('bar', <unbound method foo.bar>)]
So, my question is, why exactly is baz not considered a method and how can I modify getmethods.py to get the following output:
[('__init__', <unbound method foo.__init__>), ('bar', <unbound method foo.bar>), ('baz', <property object at 0x7fbc1a73d260>)]
The @property decorator produces a property object, not a function or a method. It is this object that calls the function it has stored in the .fget, .fset and .fdel attributes on that object when accessed (through the descriptor protocol).
You'll have to explicitly test for that object type:
methods = inspect.getmembers(cls[1], inspect.ismethod)
properties = inspect.getmembers(cls[1], lambda o: isinstance(o, property))
or
methods_and_properties = inspect.getmembers(
cls[1], lambda o: isinstance(o, (property, types.MethodType)))
Note that the same limitations apply to classmethod and staticmethod objects.