Reputation: 12861
I want to iterate through the methods in a class, or handle class or instance objects differently based on the methods present. How do I get a list of class methods?
Also see:
Upvotes: 485
Views: 612370
Reputation: 1846
For my use case, I needed to distinguish between class methods, static methods, properties, and instance methods. The inspect module confuses the issue a bit (particularly with class methods and instance methods), so I used vars
based on a comment on this SO question. The basic gist is to use vars
to get the __dict__
attribute of the class, then filter based on various isinstance
checks. For instance methods, I check that it is callable
and not a class method. One caveat: this approach of using vars
(or __dict__
for that matter) won't work with __slots__
. Using Python 3.6.9 (because it's what the Docker image I'm using as my interpreter has):
class MethodAnalyzer:
class_under_test = None
@classmethod
def get_static_methods(cls):
if cls.class_under_test:
return {
k for k, v in vars(cls.class_under_test).items()
if isinstance(v, staticmethod)
}
return {}
@classmethod
def get_class_methods(cls):
if cls.class_under_test:
return {
k for k, v in vars(cls.class_under_test).items()
if isinstance(v, classmethod)
}
return {}
@classmethod
def get_instance_methods(cls):
if cls.class_under_test:
return {
k for k, v in vars(cls.class_under_test).items()
if callable(v) and not isinstance(v, classmethod)
}
return {}
@classmethod
def get_properties(cls):
if cls.class_under_test:
return {
k for k, v in vars(cls.class_under_test).items()
if isinstance(v, property)
}
return {}
To see it in action, I created this little test class:
class Foo:
@staticmethod
def bar(baz):
print(baz)
@property
def bleep(self):
return 'bloop'
@classmethod
def bork(cls):
return cls.__name__
def flank(self):
return 'on your six'
then did:
MethodAnalyzer.class_under_test = Foo
print(MethodAnalyzer.get_instance_methods())
print(MethodAnalyzer.get_class_methods())
print(MethodAnalyzer.get_static_methods())
print(MethodAnalyzer.get_properties())
which output
{'flank'}
{'bork'}
{'bar'}
{'bleep'}
In this example I'm discarding the actual methods, but if you needed to keep them you could just use a dict comprehension instead of a set comprehension:
{
k, v for k, v in vars(cls.class_under_test).items()
if callable(v) and not isinstance(v, classmethod)
}
Upvotes: 0
Reputation: 33
Just like this
pprint.pprint([x for x in dir(list) if not x.startswith("_")])
Upvotes: -1
Reputation: 4233
use inspect.ismethod and dir and getattr
import inspect
class ClassWithMethods:
def method1(self):
print('method1')
def method2(self):
print('method2')
obj=ClassWithMethods()
method_names = [attr for attr in dir(obj) if inspect.ismethod(getattr(obj,attr))
print(method_names)
output:
[[('method1', <bound method ClassWithMethods.method1 of <__main__.ClassWithMethods object at 0x00000266779AF388>>), ('method2', <bound method ClassWithMethods.method2 of <__main__.ClassWithMethods object at 0x00000266779AF388>>)]]
Upvotes: 1
Reputation: 91
None of the above worked for me.
I've encountered this problem while writing pytests.
The only work-around I found was to:
1- create another directory and place all my .py files there
2- create a separate directory for my pytests and then importing the classes I'm interested in
This allowed me to get up-to-dated methods within the class - you can change the method names and then use print(dir(class))
to confirm it.
Upvotes: 0
Reputation: 2133
This also works:
In mymodule.py
:
def foo(x):
return 'foo'
def bar():
return 'bar'
In another file:
import inspect
import mymodule
method_list = [ func[0] for func in inspect.getmembers(mymodule, predicate=inspect.isroutine) if callable(getattr(mymodule, func[0])) ]
Output:
['foo', 'bar']
From the Python docs:
inspect.isroutine(object)
Return true if the object is a user-defined or built-in function or method.
Upvotes: 7
Reputation: 31
You can use a function which I have created.
def method_finder(classname):
non_magic_class = []
class_methods = dir(classname)
for m in class_methods:
if m.startswith('__'):
continue
else:
non_magic_class.append(m)
return non_magic_class
method_finder(list)
Output:
['append',
'clear',
'copy',
'count',
'extend',
'index',
'insert',
'pop',
'remove',
'reverse',
'sort']
Upvotes: 3
Reputation: 6476
If your method is a "regular" method and not a staticmethod
, classmethod
etc.
There is a little hack I came up with -
for k, v in your_class.__dict__.items():
if "function" in str(v):
print(k)
This can be extended to other type of methods by changing "function" in the if
condition correspondingly.
Tested in Python 2.7 and Python 3.5.
Upvotes: 11
Reputation: 2456
There's this approach:
[getattr(obj, m) for m in dir(obj) if not m.startswith('__')]
When dealing with a class instance, perhaps it'd be better to return a list with the method references instead of just names¹. If that's your goal, as well as
import
__init__
) from the listIt may be of use. You might also want to assure it's callable(getattr(obj, m))
, since dir
returns all attributes within obj
, not just methods.
In a nutshell, for a class like
class Ghost:
def boo(self, who):
return f'Who you gonna call? {who}'
We could check instance retrieval with
>>> g = Ghost()
>>> methods = [getattr(g, m) for m in dir(g) if not m.startswith('__')]
>>> print(methods)
[<bound method Ghost.boo of <__main__.Ghost object at ...>>]
So you can call it right away:
>>> for method in methods:
... print(method('GHOSTBUSTERS'))
...
Who you gonna call? GHOSTBUSTERS
¹ An use case:
I used this for unit testing. Had a class where all methods performed variations of the same process - which led to lengthy tests, each only a tweak away from the others. DRY was a far away dream.
Thought I should have a single test for all methods, so I made the above iteration.
Although I realized I should instead refactor the code itself to be DRY-compliant anyway... this may still serve a random nitpicky soul in the future.
Upvotes: 6
Reputation: 1
To produce a list of methods put the name of the method in a list without the usual parenthesis. Remove the name and attach the parenthesis and that calls the method.
def methodA():
print("@ MethodA")
def methodB():
print("@ methodB")
a = []
a.append(methodA)
a.append(methodB)
for item in a:
item()
Upvotes: -1
Reputation: 559
You can list all methods in a python class by using the following code
dir(className)
This will return a list of all the names of the methods in the class
Upvotes: 30
Reputation: 1009
I just keep this there, because top rated answers are not clear.
This is simple test with not usual class based on Enum.
# -*- coding: utf-8 -*-
import sys, inspect
from enum import Enum
class my_enum(Enum):
"""Enum base class my_enum"""
M_ONE = -1
ZERO = 0
ONE = 1
TWO = 2
THREE = 3
def is_natural(self):
return (self.value > 0)
def is_negative(self):
return (self.value < 0)
def is_clean_name(name):
return not name.startswith('_') and not name.endswith('_')
def clean_names(lst):
return [ n for n in lst if is_clean_name(n) ]
def get_items(cls,lst):
try:
res = [ getattr(cls,n) for n in lst ]
except Exception as e:
res = (Exception, type(e), e)
pass
return res
print( sys.version )
dir_res = clean_names( dir(my_enum) )
inspect_res = clean_names( [ x[0] for x in inspect.getmembers(my_enum) ] )
dict_res = clean_names( my_enum.__dict__.keys() )
print( '## names ##' )
print( dir_res )
print( inspect_res )
print( dict_res )
print( '## items ##' )
print( get_items(my_enum,dir_res) )
print( get_items(my_enum,inspect_res) )
print( get_items(my_enum,dict_res) )
And this is output results.
3.7.7 (default, Mar 10 2020, 13:18:53)
[GCC 9.2.1 20200306]
## names ##
['M_ONE', 'ONE', 'THREE', 'TWO', 'ZERO']
['M_ONE', 'ONE', 'THREE', 'TWO', 'ZERO', 'name', 'value']
['is_natural', 'is_negative', 'M_ONE', 'ZERO', 'ONE', 'TWO', 'THREE']
## items ##
[<my_enum.M_ONE: -1>, <my_enum.ONE: 1>, <my_enum.THREE: 3>, <my_enum.TWO: 2>, <my_enum.ZERO: 0>]
(<class 'Exception'>, <class 'AttributeError'>, AttributeError('name'))
[<function my_enum.is_natural at 0xb78a1fa4>, <function my_enum.is_negative at 0xb78ae854>, <my_enum.M_ONE: -1>, <my_enum.ZERO: 0>, <my_enum.ONE: 1>, <my_enum.TWO: 2>, <my_enum.THREE: 3>]
So what we have:
dir
provide not complete datainspect.getmembers
provide not complete data and provide internal keys that are not accessible with getattr()
__dict__.keys()
provide complete and reliable resultWhy are votes so erroneous? And where i'm wrong? And where wrong other people which answers have so low votes?
Upvotes: 9
Reputation: 100756
An example (listing the methods of the optparse.OptionParser
class):
>>> from optparse import OptionParser
>>> import inspect
#python2
>>> inspect.getmembers(OptionParser, predicate=inspect.ismethod)
[([('__init__', <unbound method OptionParser.__init__>),
...
('add_option', <unbound method OptionParser.add_option>),
('add_option_group', <unbound method OptionParser.add_option_group>),
('add_options', <unbound method OptionParser.add_options>),
('check_values', <unbound method OptionParser.check_values>),
('destroy', <unbound method OptionParser.destroy>),
('disable_interspersed_args',
<unbound method OptionParser.disable_interspersed_args>),
('enable_interspersed_args',
<unbound method OptionParser.enable_interspersed_args>),
('error', <unbound method OptionParser.error>),
('exit', <unbound method OptionParser.exit>),
('expand_prog_name', <unbound method OptionParser.expand_prog_name>),
...
]
# python3
>>> inspect.getmembers(OptionParser, predicate=inspect.isfunction)
...
Notice that getmembers
returns a list of 2-tuples. The first item is the name of the member, the second item is the value.
You can also pass an instance to getmembers
:
>>> parser = OptionParser()
>>> inspect.getmembers(parser, predicate=inspect.ismethod)
...
Upvotes: 452
Reputation: 883
This is just an observation. "encode" seems to be a method for string objects
str_1 = 'a'
str_1.encode('utf-8')
>>> b'a'
However, if str1 is inspected for methods, an empty list is returned
inspect.getmember(str_1, predicate=inspect.ismethod)
>>> []
So, maybe I am wrong, but the issue seems to be not simple.
Upvotes: -1
Reputation: 12333
methods = [(func, getattr(o, func)) for func in dir(o) if callable(getattr(o, func))]
gives an identical list as
methods = inspect.getmembers(o, predicate=inspect.ismethod)
does.
Upvotes: 3
Reputation: 3502
If you want to list only methods of a python class
import numpy as np
print(np.random.__all__)
Upvotes: -6
Reputation: 7948
class CPerson:
def __init__(self, age):
self._age = age
def run(self):
pass
@property
def age(self): return self._age
@staticmethod
def my_static_method(): print("Life is short, you need Python")
@classmethod
def say(cls, msg): return msg
test_class = CPerson
# print(dir(test_class)) # list all the fields and methods of your object
print([(name, t) for name, t in test_class.__dict__.items() if type(t).__name__ == 'function' and not name.startswith('__')])
print([(name, t) for name, t in test_class.__dict__.items() if type(t).__name__ != 'function' and not name.startswith('__')])
output
[('run', <function CPerson.run at 0x0000000002AD3268>)]
[('age', <property object at 0x0000000002368688>), ('my_static_method', <staticmethod object at 0x0000000002ACBD68>), ('say', <classmethod object at 0x0000000002ACF0B8>)]
Upvotes: -2
Reputation: 1033
Say you want to know all methods associated with list class Just Type The following
print (dir(list))
Above will give you all methods of list class
Upvotes: 64
Reputation: 2993
Python 3.x answer without external libraries
method_list = [func for func in dir(Foo) if callable(getattr(Foo, func))]
dunder-excluded result:
method_list = [func for func in dir(Foo) if callable(getattr(Foo, func)) and not func.startswith("__")]
Upvotes: 233
Reputation: 3517
you can also import the FunctionType from types and test it with the class.__dict__
:
from types import FunctionType
class Foo:
def bar(self): pass
def baz(self): pass
def methods(cls):
return [x for x, y in cls.__dict__.items() if type(y) == FunctionType]
methods(Foo) # ['bar', 'baz']
Upvotes: 34
Reputation: 49
def find_defining_class(obj, meth_name):
for ty in type(obj).mro():
if meth_name in ty.__dict__:
return ty
So
print find_defining_class(car, 'speedometer')
Think Python page 210
Upvotes: 3
Reputation: 7115
There is the dir(theobject)
method to list all the fields and methods of your object (as a tuple) and the inspect module (as codeape write) to list the fields and methods with their doc (in """).
Because everything (even fields) might be called in Python, I'm not sure there is a built-in function to list only methods. You might want to try if the object you get through dir
is callable or not.
Upvotes: 301
Reputation: 665
Note that you need to consider whether you want methods from base classes which are inherited (but not overridden) included in the result. The dir()
and inspect.getmembers()
operations do include base class methods, but use of the __dict__
attribute does not.
Upvotes: 15
Reputation: 39
I know this is an old post, but just wrote this function and will leave it here is case someone stumbles looking for an answer:
def classMethods(the_class,class_only=False,instance_only=False,exclude_internal=True):
def acceptMethod(tup):
#internal function that analyzes the tuples returned by getmembers tup[1] is the
#actual member object
is_method = inspect.ismethod(tup[1])
if is_method:
bound_to = tup[1].im_self
internal = tup[1].im_func.func_name[:2] == '__' and tup[1].im_func.func_name[-2:] == '__'
if internal and exclude_internal:
include = False
else:
include = (bound_to == the_class and not instance_only) or (bound_to == None and not class_only)
else:
include = False
return include
#uses filter to return results according to internal function and arguments
return filter(acceptMethod,inspect.getmembers(the_class))
Upvotes: 1