A better way to search for methods of Python objects

Python’s introspection abilities are quite extensive and useful. They are also well-documented, so I won’t go into the basics here. Check out this article if you need a good overview. N.B.: discussion and code below applies to both methods and attributes. I will simply refer to “methods” for simplicity.

Beyond simply listing the methods of an object, however, I often find that I want to search through them for something in particular. And eyeballing the output of dir(obj) is only efficient in the simplest of cases. hasattr(obj, “method”) won’t get you far either, as you need to match the “method” name exactly. What if you just have a good guess about the name of a method based on what you need to do? What if you want to know everything you can do with directories in the os module or ISO related methods in datetime.date? I haven’t found anything to help with this sort of problem yet. Approaches like writing a loop to do the search every time or perusing the pertinent API docs are too circuitous for such quick questions. So let’s make a tool to do this more easily!

We start with knowing some object and some string containing all or part of the method(s) we’re interested in:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def mf(obj, term):
    """
    Searches through the methods and attributes defined for obj,
    looks for those containing the term passed.
    Returns all matches or a warning if none found.
    """

    meths = dir(obj)
    match_meths = []
    for meth in meths:
        if meth.rfind(term) != -1:
            match_meths.append(meth)
    if match_meths:
        print match_meths
    else:
        print "No matches!"

This simply iterates over the methods and attributes defined for the object passed and looks for the term passed within the name of each. rfind returns the highest index of the substring passed in the string it’s called on and returns -1 if no match is found. Once the matches are collected they are printed out. An example:

1
2
3
4
>>>from method_finder import mf
>>>import os
>>>mf(os, "dir")
['chdir', 'curdir', 'fchdir', 'listdir', 'makedirs', 'mkdir', 'pardir', 'removedirs', 'rmdir']

For convenience let’s make it available on the Python interactive prompt at every load without any extra effort. This is easy enough using a .pythonstartup file. This file can be used to load various useful items like tab completion for interactive Python sessions. If you haven’t used it before, you’ll need to add the following to your .bashrc:

1
export PYTHONSTARTUP="$HOME/.pythonstartup"

Then in your home directory create a .pythonstartup file containing something like the following:

1
2
3
4
5
6
7
8
9
10
11
import os
# Adds mf(obj, "str") allowing search for methods matching 'str' on obj
# as well as obinfo(obj) returning lots of info on obj
util_loc = "/home/shuckins/code/code_homerepo/python-programming/utilities"
if os.path.isdir(util_loc):
    import sys
    sys.path.append(util_loc)
    from utils import mf, obinfo
    sys.path.remove(util_loc)
    del sys
del os

You’ll need to change the path specified to wherever you placed utils.py containing the mf() function of course. You can download mine here if you’d like. The del statements are to clean up any trace of this operation once you get to the interactive interpreter. This way you get the added functions without mucking up your namespace.

This also loads in an obinfo(obj) function that I included in the same utils.py file. This is based on the interrogate() function written by Patrick O’Brien in the introspection article mentioned above. My version just adds a check for objects without docstrings and prints more of the docstring:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def obinfo(obj):
    """
    Print useful information about object.

    From http://www.ibm.com/developerworks/library/l-pyint.html
    """

    if hasattr(obj, '__name__'):
        print "NAME:    ", obj.__name__
    if hasattr(obj, '__class__'):
        print "CLASS:   ", obj.__class__.__name__
    print "ID:      ", id(obj)
    print "TYPE:    ", type(obj)
    print "VALUE:   ", repr(obj)
    print "CALLABLE:",
    if callable(obj):
        print "Yes"
    else:
        print "No"
    if hasattr(obj, '__doc__'):
        doc = getattr(obj, '__doc__')
        doc = doc.strip()
        topfive = doc.split('\n')[0:4]
        print "DOC:     ", "\n".join(topfive)
    else:
        print "No docstring. Yell at the author."

It’s fairly useful:

1
2
3
4
5
6
7
8
>>> obinfo(["some", "list"].count)
NAME:     count
CLASS:    builtin_function_or_method
ID:       139922087930696
TYPE:     <type 'builtin_function_or_method'>
VALUE:    <built-in method count of list object at 0x7f422658ef80>
CALLABLE: Yes
DOC:      L.count(value) -> integer -- return number of occurrences of value

Post to Twitter Post to Delicious Post to Digg Post to Reddit

No related posts.

Related posts brought to you by Yet Another Related Posts Plugin.

This entry was posted in Programming, Python and tagged , , . Bookmark the permalink.

4 Responses to A better way to search for methods of Python objects

  1. Thanks for this! I took the liberty of including this in the jaraco.util package under the jaraco.lang.python module (see https://svn.jaraco.com/jaraco/python/jaraco.util/jaraco/lang/python.py ).

    One change I made was to make ‘mf’ case-insensitive, because most of the time I don’t care about the case when I’m searching for a method or attribute.

  2. @Jason Glad you also found it useful! The changes you made were helpful, thanks.

  3. Johan says:

    http://github.com/inky/see
    An alternative to Python’s dir(). Easy to type; easy to read! For humans only.

  4. @Johan I like it! I’ll be checking out see() more, looks quite helpful.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>